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.remoteaccess.CarRemoteAccessManager.TASK_TYPE_CUSTOM;
20 import static android.car.remoteaccess.CarRemoteAccessManager.TASK_TYPE_ENTER_GARAGE_MODE;
21 import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_UNLOCKED;
22 import static android.content.Context.BIND_AUTO_CREATE;
23 import static android.content.Context.RECEIVER_NOT_EXPORTED;
24 
25 import static com.android.car.CarServiceUtils.isEventOfType;
26 import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.BOILERPLATE_CODE;
27 import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.DUMP_INFO;
28 import static com.android.car.internal.common.CommonConstants.EMPTY_INT_ARRAY;
29 
30 import android.annotation.Nullable;
31 import android.app.ActivityManager;
32 import android.car.Car;
33 import android.car.builtin.os.HandlerHelper;
34 import android.car.builtin.util.Slogf;
35 import android.car.feature.FeatureFlags;
36 import android.car.feature.FeatureFlagsImpl;
37 import android.car.hardware.power.CarPowerManager;
38 import android.car.hardware.power.ICarPowerStateListener;
39 import android.car.remoteaccess.CarRemoteAccessManager;
40 import android.car.remoteaccess.ICarRemoteAccessCallback;
41 import android.car.remoteaccess.ICarRemoteAccessService;
42 import android.car.remoteaccess.RemoteTaskClientRegistrationInfo;
43 import android.car.remoteaccess.TaskScheduleInfo;
44 import android.car.user.CarUserManager.UserLifecycleListener;
45 import android.car.user.UserLifecycleEventFilter;
46 import android.content.BroadcastReceiver;
47 import android.content.ComponentName;
48 import android.content.Context;
49 import android.content.Intent;
50 import android.content.IntentFilter;
51 import android.content.ServiceConnection;
52 import android.content.pm.PackageManager;
53 import android.content.pm.PackageManager.PackageInfoFlags;
54 import android.content.pm.ResolveInfo;
55 import android.content.pm.ServiceInfo;
56 import android.content.res.XmlResourceParser;
57 import android.hardware.automotive.remoteaccess.IRemoteAccess;
58 import android.hardware.automotive.remoteaccess.ScheduleInfo;
59 import android.hardware.automotive.remoteaccess.TaskType;
60 import android.net.Uri;
61 import android.os.Binder;
62 import android.os.Handler;
63 import android.os.HandlerThread;
64 import android.os.IBinder;
65 import android.os.Looper;
66 import android.os.Message;
67 import android.os.RemoteException;
68 import android.os.ServiceSpecificException;
69 import android.os.SystemClock;
70 import android.os.UserHandle;
71 import android.os.UserManager;
72 import android.util.ArrayMap;
73 import android.util.ArraySet;
74 import android.util.Log;
75 import android.util.SparseArray;
76 import android.util.proto.ProtoOutputStream;
77 
78 import com.android.car.CarLocalServices;
79 import com.android.car.CarLog;
80 import com.android.car.CarServiceBase;
81 import com.android.car.CarServiceUtils;
82 import com.android.car.R;
83 import com.android.car.hal.PowerHalService;
84 import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport;
85 import com.android.car.internal.util.IndentingPrintWriter;
86 import com.android.car.power.CarPowerManagementService;
87 import com.android.car.remoteaccess.RemoteAccessStorage.ClientIdEntry;
88 import com.android.car.remoteaccess.hal.RemoteAccessHalCallback;
89 import com.android.car.remoteaccess.hal.RemoteAccessHalWrapper;
90 import com.android.car.systeminterface.SystemInterface;
91 import com.android.car.user.CarUserService;
92 import com.android.internal.annotations.GuardedBy;
93 import com.android.internal.annotations.VisibleForTesting;
94 import com.android.internal.util.Preconditions;
95 
96 import org.xmlpull.v1.XmlPullParser;
97 import org.xmlpull.v1.XmlPullParserException;
98 
99 import java.io.IOException;
100 import java.lang.ref.WeakReference;
101 import java.time.Duration;
102 import java.util.ArrayList;
103 import java.util.List;
104 import java.util.Set;
105 import java.util.concurrent.atomic.AtomicLong;
106 import java.util.concurrent.atomic.AtomicReference;
107 
108 /**
109  * Service to implement CarRemoteAccessManager API.
110  */
111 public final class CarRemoteAccessService extends ICarRemoteAccessService.Stub
112         implements CarServiceBase {
113 
114     private static final String TAG = CarLog.tagFor(CarRemoteAccessService.class);
115     private static final boolean DEBUG = Slogf.isLoggable(TAG, Log.DEBUG);
116 
117     // Tag names for remote_access_serverless_client_map.xml.
118     private static final String XML_TAG_CLIENT_ID = "ClientId";
119     private static final String XML_TAG_PACKAGE_NAME = "PackageName";
120     private static final String XML_TAG_SERVERLESS_CLIENT = "ServerlessClient";
121     private static final String XML_TAG_SERVERLESS_CLIENT_MAP = "ServerlessClientMap";
122 
123     private static final int MILLI_TO_SECOND = 1000;
124     private static final String TASK_PREFIX = "task";
125     private static final String CLIENT_PREFIX = "client";
126     private static final int RANDOM_STRING_LENGTH = 12;
127     private static final int MIN_SYSTEM_UPTIME_FOR_REMOTE_ACCESS_IN_SEC = 30;
128     private static final Duration PACKAGE_SEARCH_DELAY = Duration.ofSeconds(1);
129     // Add some randomness to package search delay to avoid thundering herd issue.
130     private static final Duration PACKAGE_SEARCH_DELAY_RAND_RANGE = Duration.ofMillis(100);
131     // Remote task client can use up to 30 seconds to initialize and upload necessary info to the
132     // server.
133     private static final long ALLOWED_TIME_FOR_REMOTE_TASK_CLIENT_INIT_MS = 30_000;
134     private static final long SHUTDOWN_WARNING_MARGIN_IN_MS = 5000;
135     private static final long INVALID_ALLOWED_SYSTEM_UPTIME = -1;
136     private static final int DEFAULT_NOTIFY_AP_STATE_RETRY_SLEEP_IN_MS = 100;
137     private static final int DEFAULT_NOTIFY_AP_STATE_MAX_RETRY = 10;
138     // The buffer time after all the tasks for a specific remote task client service is completed
139     // before we unbind the service.
140     private static final int TASK_UNBIND_DELAY_MS = 1000;
141     // The max time in ms allowed for a task after it is received by the car service, before the
142     // remote task client service is started and it is delivered to that service. This period will
143     // include waiting for the remote task client service to be started if it is not already bound.
144     private static final int MAX_TASK_PENDING_MS = 60_000;
145 
146     private final Object mLock = new Object();
147     private final Context mContext;
148     private final PackageManager mPackageManager;
149     private final HandlerThread mHandlerThread =
150             CarServiceUtils.getHandlerThread(getClass().getSimpleName());
151     private final RemoteTaskClientServiceHandler mHandler =
152             new RemoteTaskClientServiceHandler(mHandlerThread.getLooper(), this);
153     private long mAllowedTimeForRemoteTaskClientInitMs =
154             ALLOWED_TIME_FOR_REMOTE_TASK_CLIENT_INIT_MS;
155     private long mTaskUnbindDelayMs = TASK_UNBIND_DELAY_MS;
156     private long mMaxTaskPendingMs = MAX_TASK_PENDING_MS;
157     private final AtomicLong mTaskCount = new AtomicLong(/* initialValue= */ 0);
158     private final AtomicLong mClientCount = new AtomicLong(/* initialValue= */ 0);
159     // Whether in vehicle task scheduling is supported by remote access HAL. Only set during init.
160     private boolean mIsHalTaskScheduleSupported;
161     @GuardedBy("mLock")
162     private final ArrayMap<String, String> mUidByClientId = new ArrayMap<>();
163     @GuardedBy("mLock")
164     private final ArrayMap<String, ArrayList<RemoteTask>> mTasksToBeNotifiedByClientId =
165             new ArrayMap<>();
166     @GuardedBy("mLock")
167     private final ArrayMap<String, ClientToken> mClientTokenByUidName = new ArrayMap<>();
168     @GuardedBy("mLock")
169     private final ArrayMap<String, RemoteTaskClientServiceInfo> mClientServiceInfoByUid =
170             new ArrayMap<>();
171     @GuardedBy("mLock")
172     private boolean mIsReadyForRemoteTask;
173     @GuardedBy("mLock")
174     private boolean mIsWakeupRequired;
175     @GuardedBy("mLock")
176     private int mNotifyApStateChangeRetryCount;
177     @GuardedBy("mLock")
178     private final ArrayMap<String, Integer> mUidByName = new ArrayMap<>();
179     @GuardedBy("mLock")
180     private final SparseArray<String> mNameByUid = new SparseArray<>();
181     @GuardedBy("mLock")
182     private ArrayMap<String, String> mServerlessClientIdsByPackageName = new ArrayMap<>();
183 
184     private final RemoteAccessStorage mRemoteAccessStorage;
185 
186     private FeatureFlags mFeatureFlags = new FeatureFlagsImpl();
187 
188     /**
189      * Sets fake feature flag for unit testing.
190      */
191     @VisibleForTesting
setFeatureFlags(FeatureFlags fakeFeatureFlags)192     public void setFeatureFlags(FeatureFlags fakeFeatureFlags) {
193         mFeatureFlags = fakeFeatureFlags;
194     }
195 
196     private final ICarPowerStateListener mCarPowerStateListener =
197             new ICarPowerStateListener.Stub() {
198         @Override
199         public void onStateChanged(int state, long expirationTimeMs) {
200             // isReadyForRemoteTask and isWakeupRequired are only valid when apStateChangeRequired
201             // is true.
202             Slogf.i(TAG, "power state change, new state: %d", state);
203             boolean apStateChangeRequired = false;
204             boolean isReadyForRemoteTask = false;
205             boolean isWakeupRequired = false;
206             boolean needsComplete = false;
207 
208             switch (state) {
209                 case CarPowerManager.STATE_SHUTDOWN_PREPARE:
210                     apStateChangeRequired = true;
211                     isReadyForRemoteTask = false;
212                     isWakeupRequired = false;
213 
214                     needsComplete = true;
215                     // If this shutdown is initiated by remote access service, then all remote task
216                     // client services should already be unbound and this will do nothing. This is
217                     // useful for cases when the shutdown is not initiated by us (e.g. by user).
218                     unbindAllServices();
219                     break;
220                 case CarPowerManager.STATE_WAIT_FOR_VHAL:
221                 case CarPowerManager.STATE_SUSPEND_EXIT:
222                 case CarPowerManager.STATE_HIBERNATION_EXIT:
223                     apStateChangeRequired = true;
224                     isReadyForRemoteTask = true;
225                     isWakeupRequired = false;
226                     break;
227                 case CarPowerManager.STATE_POST_SHUTDOWN_ENTER:
228                 case CarPowerManager.STATE_POST_SUSPEND_ENTER:
229                 case CarPowerManager.STATE_POST_HIBERNATION_ENTER:
230                     apStateChangeRequired = true;
231                     isReadyForRemoteTask = false;
232                     isWakeupRequired = true;
233 
234                     needsComplete = true;
235                     break;
236             }
237             if (apStateChangeRequired) {
238                 synchronized (mLock) {
239                     mIsReadyForRemoteTask = isReadyForRemoteTask;
240                     mIsWakeupRequired = isWakeupRequired;
241                 }
242                 mHandler.cancelNotifyApStateChange();
243                 if (!mRemoteAccessHalWrapper.notifyApStateChange(
244                         isReadyForRemoteTask, isWakeupRequired)) {
245                     Slogf.e(TAG, "Cannot notify AP state change according to power state(%d)",
246                             state);
247                 }
248             }
249             if (needsComplete) {
250                 mPowerService.finished(state, this);
251             }
252         }
253     };
254 
255     @GuardedBy("mLock")
isServerlessClientLocked(String clientId)256     private boolean isServerlessClientLocked(String clientId) {
257         for (int i = 0; i < mServerlessClientIdsByPackageName.size(); i++) {
258             if (mServerlessClientIdsByPackageName.valueAt(i).equals(clientId)) {
259                 return true;
260             }
261         }
262         return false;
263     }
264 
maybeStartNewRemoteTask(String clientId)265     private void maybeStartNewRemoteTask(String clientId) {
266         ICarRemoteAccessCallback callback;
267         List<RemoteTask> remoteTasksToNotify = null;
268         RemoteTaskClientServiceInfo serviceInfo = null;
269         int taskMaxDurationInSec;
270         long taskMaxDurationInMs;
271         String uidName;
272         ClientToken token;
273 
274         synchronized (mLock) {
275             if (mTasksToBeNotifiedByClientId.get(clientId) == null) {
276                 return;
277             }
278             taskMaxDurationInMs = calcTaskMaxDurationInMsLocked();
279             taskMaxDurationInSec = (int) (taskMaxDurationInMs / MILLI_TO_SECOND);
280             if (taskMaxDurationInSec <= 0) {
281                 Slogf.w(TAG, "onRemoteTaskRequested: system shutdown was supposed to start, "
282                             + "but still on: expected shutdown time=%d, current time=%d",
283                             mShutdownTimeInMs, SystemClock.uptimeMillis());
284                 // Remove all tasks for this client ID.
285                 Slogf.w(TAG, "Removing all the pending tasks for client ID: %s", clientId);
286                 mTasksToBeNotifiedByClientId.remove(clientId);
287                 return;
288             }
289             // If this clientId has never been stored on this device before,
290             uidName = mUidByClientId.get(clientId);
291             // uidName might be null for serverless remote task client if the device just booted up
292             // and the client has not called addCarRemoteTaskClient yet. For regular remote task
293             // client, the client ID must already be stored in database, so during
294             // populatePackageClientIdMapping the mUidByClientId will contain clientId and uidName
295             // must not be null.
296             if (!isServerlessClientLocked(clientId) && uidName == null) {
297                 Slogf.w(TAG, "Cannot notify task: client(%s) is not registered.", clientId);
298                 Slogf.w(TAG, "Removing all the pending tasks for client ID: %s", clientId);
299                 mTasksToBeNotifiedByClientId.remove(clientId);
300                 return;
301             }
302             if (uidName != null) {
303                 serviceInfo = mClientServiceInfoByUid.get(uidName);
304             }
305             if (serviceInfo == null) {
306                 Slogf.w(TAG, "Notifying task is delayed: the remote client service information "
307                         + "for %s is not registered yet", clientId);
308                 // We don't have to start the service explicitly because it will be started
309                 // after searching for remote task client service is done.
310                 return;
311             }
312             // Token must not be null if mUidByClientId contains clientId.
313             token = mClientTokenByUidName.get(uidName);
314             callback = token.getCallback();
315             if (callback != null) {
316                 remoteTasksToNotify = popTasksFromPendingQueueLocked(clientId);
317             }
318         }
319         // Always try to bind the remote task client service. This will starts the service if
320         // it is not active. This will also keep the service alive during the task period.
321         startRemoteTaskClientService(serviceInfo, uidName, taskMaxDurationInMs);
322 
323         if (callback == null) {
324             Slogf.w(TAG, "Notifying task is delayed: the callback for token: %s "
325                     + "is not registered yet", token);
326             return;
327         }
328 
329         if (remoteTasksToNotify != null && !remoteTasksToNotify.isEmpty()) {
330             invokeTaskRequestCallbacks(serviceInfo.getServiceConnection(), callback, clientId,
331                     remoteTasksToNotify, taskMaxDurationInSec);
332         }
333     }
334 
335     private final RemoteAccessHalCallback mHalCallback = new RemoteAccessHalCallback() {
336         @Override
337         public void onRemoteTaskRequested(String clientId, byte[] data) {
338             if (DEBUG) {
339                 Slogf.d(TAG, "Remote task is requested through the HAL to client(%s)", clientId);
340             }
341             String taskId = generateNewTaskId();
342             long now = SystemClock.uptimeMillis();
343             long timeoutInMs = now + mMaxTaskPendingMs;
344             synchronized (mLock) {
345                 pushTaskToPendingQueueLocked(clientId, new RemoteTask(taskId, data, clientId,
346                         timeoutInMs));
347             }
348             maybeStartNewRemoteTask(clientId);
349         }
350     };
351     private RemoteAccessHalWrapper mRemoteAccessHalWrapper;
352     private PowerHalService mPowerHalService;
353     private final UserManager mUserManager;
354     private final long mShutdownTimeInMs;
355     private final long mAllowedSystemUptimeMs;
356     private final int mNotifyApStateChangeMaxRetry;
357     private final int mNotifyApStateChangeRetrySleepInMs;
358     private final BroadcastReceiver mPackageRemovedReceiver;
359 
360     private String mWakeupServiceName = "";
361     private String mVehicleId = "";
362     private String mProcessorId = "";
363     @GuardedBy("mLock")
364     private int mNextPowerState;
365     @GuardedBy("mLock")
366     private boolean mRunGarageMode;
367     private CarPowerManagementService mPowerService;
368 
369     private CarRemoteAccessServiceDep mDep;
370 
CarRemoteAccessService(Context context, SystemInterface systemInterface, PowerHalService powerHalService)371     public CarRemoteAccessService(Context context, SystemInterface systemInterface,
372             PowerHalService powerHalService) {
373         this(context, systemInterface, powerHalService, /* dep= */ null,
374                 /* remoteAccessHal= */ null, /* remoteAccessStorage= */ null,
375                 INVALID_ALLOWED_SYSTEM_UPTIME, /* inMemoryStorage= */ false);
376     }
377 
378     /**
379      * Dependencies for stubbing.
380      */
381     @VisibleForTesting
382     public interface CarRemoteAccessServiceDep {
383         /**
384          * Gets the calling UID. Must be used in a binder context.
385          */
getCallingUid()386         int getCallingUid();
387 
388         /**
389          * Gets the current user.
390          */
getCurrentUser()391         int getCurrentUser();
392     }
393 
394     @ExcludeFromCodeCoverageGeneratedReport(reason = BOILERPLATE_CODE)
395     private static class CarRemoteAccessServiceDepImpl implements CarRemoteAccessServiceDep {
getCallingUid()396         public int getCallingUid() {
397             return Binder.getCallingUid();
398         }
399 
getCurrentUser()400         public int getCurrentUser() {
401             return ActivityManager.getCurrentUser();
402         }
403     }
404 
405     @VisibleForTesting
CarRemoteAccessService(Context context, SystemInterface systemInterface, PowerHalService powerHalService, @Nullable CarRemoteAccessServiceDep dep, @Nullable IRemoteAccess remoteAccessHal, @Nullable RemoteAccessStorage remoteAccessStorage, long allowedSystemUptimeMs, boolean inMemoryStorage)406     public CarRemoteAccessService(Context context, SystemInterface systemInterface,
407             PowerHalService powerHalService, @Nullable CarRemoteAccessServiceDep dep,
408             @Nullable IRemoteAccess remoteAccessHal,
409             @Nullable RemoteAccessStorage remoteAccessStorage, long allowedSystemUptimeMs,
410             boolean inMemoryStorage) {
411         mContext = context;
412         mUserManager = mContext.getSystemService(UserManager.class);
413         mPowerHalService = powerHalService;
414         mDep = dep != null ? dep : new CarRemoteAccessServiceDepImpl();
415         mPackageManager = mContext.getPackageManager();
416         mRemoteAccessHalWrapper = new RemoteAccessHalWrapper(mHalCallback, remoteAccessHal);
417         mAllowedSystemUptimeMs = allowedSystemUptimeMs == INVALID_ALLOWED_SYSTEM_UPTIME
418                 ? getAllowedSystemUptimeForRemoteTaskInMs() : allowedSystemUptimeMs;
419         mShutdownTimeInMs = SystemClock.uptimeMillis() + mAllowedSystemUptimeMs;
420         mRemoteAccessStorage = remoteAccessStorage != null ? remoteAccessStorage :
421                 new RemoteAccessStorage(context, systemInterface, inMemoryStorage);
422         // TODO(b/263807920): CarService restart should be handled.
423         systemInterface.scheduleActionForBootCompleted(() -> searchForRemoteTaskClientPackages(),
424                 PACKAGE_SEARCH_DELAY, PACKAGE_SEARCH_DELAY_RAND_RANGE);
425         mNotifyApStateChangeMaxRetry = getNotifyApStateChangeMaxRetry();
426         mNotifyApStateChangeRetrySleepInMs = getNotifyApStateChangeRetrySleepInMs();
427         mPackageRemovedReceiver = new BroadcastReceiver() {
428             @Override
429             public void onReceive(Context context, Intent intent) {
430                 onReceiveIntent(context, intent);
431             }
432         };
433     }
434 
435     /**
436      * handles {@code ACTION_PACKAGE_REMOVED} intent.
437      */
438     @SuppressWarnings("unused")
onReceiveIntent(Context context, Intent intent)439     private void onReceiveIntent(Context context, Intent intent) {
440         if (!intent.getAction().equals(Intent.ACTION_PACKAGE_REMOVED)) {
441             Slogf.w(TAG, "Received an unknown intent, ignore: " + intent);
442             return;
443         }
444         String packageName = Uri.parse(intent.getDataString()).getSchemeSpecificPart();
445         String clientId;
446         synchronized (mLock) {
447             if (!mServerlessClientIdsByPackageName.containsKey(packageName)) {
448                 // Not a serverless client, ignore.
449                 return;
450             }
451             clientId = mServerlessClientIdsByPackageName.get(packageName);
452         }
453         try {
454             mRemoteAccessHalWrapper.unscheduleAllTasks(clientId);
455         } catch (ServiceSpecificException | RemoteException e) {
456             Slogf.e(TAG, e, "failed to unschedule tasks for package: %s when it is removed",
457                     packageName);
458         }
459     }
460 
461     @VisibleForTesting
setRemoteAccessHalWrapper(RemoteAccessHalWrapper remoteAccessHalWrapper)462     public void setRemoteAccessHalWrapper(RemoteAccessHalWrapper remoteAccessHalWrapper) {
463         mRemoteAccessHalWrapper = remoteAccessHalWrapper;
464     }
465 
466     @VisibleForTesting
setPowerHal(PowerHalService powerHalService)467     public void setPowerHal(PowerHalService powerHalService) {
468         mPowerHalService = powerHalService;
469     }
470 
471     @VisibleForTesting
setAllowedTimeForRemoteTaskClientInitMs(long allowedTimeForRemoteTaskClientInitMs)472     public void setAllowedTimeForRemoteTaskClientInitMs(long allowedTimeForRemoteTaskClientInitMs) {
473         mAllowedTimeForRemoteTaskClientInitMs = allowedTimeForRemoteTaskClientInitMs;
474     }
475 
476     @VisibleForTesting
setTaskUnbindDelayMs(long taskUnbindDelayMs)477     public void setTaskUnbindDelayMs(long taskUnbindDelayMs) {
478         mTaskUnbindDelayMs = taskUnbindDelayMs;
479     }
480 
481     @VisibleForTesting
setMaxTaskPendingMs(long maxTaskPendingMs)482     public void setMaxTaskPendingMs(long maxTaskPendingMs) {
483         mMaxTaskPendingMs = maxTaskPendingMs;
484     }
485 
486     @Override
init()487     public void init() {
488         mPowerService = CarLocalServices.getService(CarPowerManagementService.class);
489         populatePackageClientIdMapping();
490         mRemoteAccessHalWrapper.init();
491         // This must be called after remoteAccessHalWrapper init complete.
492         mIsHalTaskScheduleSupported = mRemoteAccessHalWrapper.isTaskScheduleSupported();
493         try {
494             mWakeupServiceName = mRemoteAccessHalWrapper.getWakeupServiceName();
495             mVehicleId = mRemoteAccessHalWrapper.getVehicleId();
496             mProcessorId = mRemoteAccessHalWrapper.getProcessorId();
497         } catch (IllegalStateException e) {
498             Slogf.e(TAG, e, "Cannot get vehicle/processor/service info from remote access HAL");
499         }
500         synchronized (mLock) {
501             mNextPowerState = getLastShutdownState();
502             mIsReadyForRemoteTask = true;
503             mIsWakeupRequired = false;
504         }
505 
506         mPowerService.registerListenerWithCompletion(mCarPowerStateListener);
507 
508         long delayForShutdowWarningMs = mAllowedSystemUptimeMs - SHUTDOWN_WARNING_MARGIN_IN_MS;
509         if (delayForShutdowWarningMs > 0) {
510             mHandler.postNotifyShutdownStarting(delayForShutdowWarningMs);
511         }
512         mHandler.postWrapUpRemoteAccessService(mAllowedSystemUptimeMs);
513         mHandler.postNotifyApStateChange(0);
514 
515         IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_REMOVED);
516         filter.addDataScheme("package");
517         // We are registering receiver for a system broadcast so the flag for NOT_EXPORTED does
518         // not really matter. But we are not expecting intents from other apps, so set it to
519         // NOT_EXPORTED to be safe.
520         mContext.registerReceiver(mPackageRemovedReceiver, filter, RECEIVER_NOT_EXPORTED);
521     }
522 
523     @Override
release()524     public void release() {
525         Slogf.i(TAG, "release CarRemoteAccessService");
526         mHandler.cancelAll();
527         mContext.unregisterReceiver(mPackageRemovedReceiver);
528         mRemoteAccessHalWrapper.release();
529         mRemoteAccessStorage.release();
530     }
531 
printMap(IndentingPrintWriter writer, ArrayMap<?, ?> map)532     private void printMap(IndentingPrintWriter writer, ArrayMap<?, ?> map) {
533         writer.increaseIndent();
534         for (int i = 0; i < map.size(); i++) {
535             writer.printf("%d: %s ==> %s\n", i, map.keyAt(i), map.valueAt(i));
536         }
537         writer.decreaseIndent();
538     }
539 
540     @Override
541     @ExcludeFromCodeCoverageGeneratedReport(reason = DUMP_INFO)
dump(IndentingPrintWriter writer)542     public void dump(IndentingPrintWriter writer) {
543         synchronized (mLock) {
544             writer.println("*Car Remote Access Service*");
545             writer.printf("mShutdownTimeInMs: %d\n", mShutdownTimeInMs);
546             writer.printf("mNextPowerState: %d\n", mNextPowerState);
547             writer.printf("mRunGarageMode: %b\n", mRunGarageMode);
548             writer.printf("mWakeupServiceName: %s\n", mWakeupServiceName);
549             writer.printf("mVehicleId: %s\n", mVehicleId);
550             writer.printf("mProcessorId: %s\n", mProcessorId);
551             writer.println("mClientTokenByUidName:");
552             printMap(writer, mClientTokenByUidName);
553             writer.println("mClientServiceInfoByUid:");
554             printMap(writer, mClientServiceInfoByUid);
555             writer.println("mUidAByName:");
556             printMap(writer, mUidByName);
557             writer.println("mUidByClientId:");
558             printMap(writer, mUidByClientId);
559             writer.println("mServerlessClientIdsByPackageName:");
560             printMap(writer, mServerlessClientIdsByPackageName);
561             writer.println("mTasksToBeNotifiedByClientId");
562             writer.increaseIndent();
563             for (int i = 0; i < mTasksToBeNotifiedByClientId.size(); i++) {
564                 String clientId = mTasksToBeNotifiedByClientId.keyAt(i);
565                 List<String> taskIds = new ArrayList<>();
566                 List<RemoteTask> tasks = mTasksToBeNotifiedByClientId.valueAt(i);
567                 for (int j = 0; j < tasks.size(); j++) {
568                     taskIds.add(tasks.get(j).id);
569                 }
570                 writer.printf("%d: %s ==> %s\n", i, clientId, taskIds);
571             }
572             writer.decreaseIndent();
573             writer.println("active task count by Uid:");
574             writer.increaseIndent();
575             for (int i = 0; i < mClientServiceInfoByUid.size(); i++) {
576                 String uidName = mClientServiceInfoByUid.keyAt(i);
577                 RemoteTaskClientServiceInfo serviceInfo = mClientServiceInfoByUid.valueAt(i);
578                 int count = 0;
579                 if (serviceInfo.getServiceConnection() != null) {
580                     count = serviceInfo.getServiceConnection().getActiveTaskCount();
581                 }
582                 writer.printf("%d: %s ==> %d\n", i, uidName, count);
583             }
584             writer.decreaseIndent();
585         }
586     }
587 
588     @Override
589     @ExcludeFromCodeCoverageGeneratedReport(reason = DUMP_INFO)
dumpProto(ProtoOutputStream proto)590     public void dumpProto(ProtoOutputStream proto) {
591         synchronized (mLock) {
592             for (int i = 0; i < mServerlessClientIdsByPackageName.size(); i++) {
593                 long fieldToken = proto.start(CarRemoteAccessDumpProto.SERVERLESS_CLIENTS);
594                 proto.write(CarRemoteAccessDumpProto.ServerlessClientInfo.CLIENT_ID,
595                         mServerlessClientIdsByPackageName.valueAt(i));
596                 proto.write(CarRemoteAccessDumpProto.ServerlessClientInfo.PACKAGE_NAME,
597                         mServerlessClientIdsByPackageName.keyAt(i));
598                 proto.end(fieldToken);
599             }
600         }
601     }
602 
getPackageNameForCallingUid(int callingUid)603     private String getPackageNameForCallingUid(int callingUid) {
604         String[] packageNames = mPackageManager.getPackagesForUid(callingUid);
605         if (packageNames.length != 1) {
606             throw new IllegalStateException("Failed to get package name, "
607                     + "sharedUserId must not be used by app.");
608         }
609         return packageNames[0];
610     }
611 
612     /**
613      * Registers {@code ICarRemoteAccessCallback}.
614      *
615      * <p>When a callback is registered for a package, calling {@code addCarRemoteTaskClient} will
616      * replace the registered callback with the new one.
617      *
618      * @param callback {@code ICarRemoteAccessCallback} that listens to remote access events.
619      * @throws IllegalArgumentException When {@code callback} is {@code null}.
620      */
621     @Override
addCarRemoteTaskClient(ICarRemoteAccessCallback callback)622     public void addCarRemoteTaskClient(ICarRemoteAccessCallback callback) {
623         CarServiceUtils.assertPermission(mContext, Car.PERMISSION_USE_REMOTE_ACCESS);
624         Preconditions.checkArgument(callback != null, "callback cannot be null");
625         int callingUid = mDep.getCallingUid();
626         ClientToken token;
627         String uidName;
628         synchronized (mLock) {
629             uidName = getNameForUidLocked(callingUid);
630             Slogf.i(TAG, "addCarRemoteTaskClient from uid: %s", uidName);
631 
632             String packageName = getPackageNameForCallingUid(callingUid);
633             boolean isServerless = mServerlessClientIdsByPackageName.containsKey(packageName);
634 
635             if (isServerless) {
636                 Slogf.i(TAG, "addCarRemoteTaskClient called from a serverless remote access "
637                         + "client: " + packageName);
638             }
639 
640             token = mClientTokenByUidName.get(uidName);
641 
642             if (isServerless && token != null
643                     && !(token.getClientId().equals(
644                             mServerlessClientIdsByPackageName.get(packageName)))) {
645                 Slogf.w(TAG, "client: " + packageName + " is a serverless remote access client "
646                         + "but has a different client ID, clear the previous client ID record");
647                 // In a rare case if the same client was previously not configured as a serverless
648                 // client, hence had a different client ID. But now it has become a serverless
649                 // remote access client. We must clear the previous record.
650                 mUidByClientId.remove(token.getClientId());
651                 mClientTokenByUidName.remove(uidName);
652                 if (token.getCallback() != null) {
653                     token.getCallback().asBinder().unlinkToDeath(token, /* flags= */ 0);
654                 }
655                 token = null;
656             }
657 
658             if (token != null) {
659                 // This is an already registered client.
660                 ICarRemoteAccessCallback oldCallback = token.getCallback();
661                 if (oldCallback != null) {
662                     oldCallback.asBinder().unlinkToDeath(token, /* flags= */ 0);
663                 }
664             } else {
665                 // This is a new client.
666                 String clientId;
667                 if (isServerless) {
668                     // This is a serverless remote task client. Use the preconfigured client ID.
669                     clientId = mServerlessClientIdsByPackageName.get(packageName);
670                 } else {
671                     // For regular remote task client, create a new random client ID.
672                     clientId = generateNewClientId();
673                 }
674                 // Creates a new client token with a null callback. The callback will be registered
675                 // in postRegistrationUpdated.
676                 token = new ClientToken(clientId, System.currentTimeMillis(), isServerless);
677                 mClientTokenByUidName.put(uidName, token);
678                 mUidByClientId.put(token.getClientId(), uidName);
679             }
680             try {
681                 callback.asBinder().linkToDeath(token, /* flags= */ 0);
682             } catch (RemoteException e) {
683                 token.setCallback(null);
684                 throw new IllegalStateException("Failed to linkToDeath callback");
685             }
686         }
687         saveClientIdInDb(token, uidName);
688         postRegistrationUpdated(callback, token);
689     }
690 
691     /**
692      * Unregisters {@code ICarRemoteAccessCallback}.
693      *
694      * @param callback {@code ICarRemoteAccessCallback} that listens to remote access events.
695      * @throws IllegalArgumentException When {@code callback} is {@code null}.
696      */
697     @Override
removeCarRemoteTaskClient(ICarRemoteAccessCallback callback)698     public void removeCarRemoteTaskClient(ICarRemoteAccessCallback callback) {
699         CarServiceUtils.assertPermission(mContext, Car.PERMISSION_USE_REMOTE_ACCESS);
700         Preconditions.checkArgument(callback != null, "callback cannot be null");
701         int callingUid = mDep.getCallingUid();
702         RemoteTaskClientServiceConnection connection = null;
703         String uidName;
704         synchronized (mLock) {
705             uidName = getNameForUidLocked(callingUid);
706             Slogf.i(TAG, "removeCarRemoteTaskClient from uid: %s", uidName);
707             ClientToken token = mClientTokenByUidName.get(uidName);
708             if (token == null) {
709                 Slogf.w(TAG, "Cannot remove callback. Callback has not been registered for %s",
710                         uidName);
711                 return;
712             }
713             if (token.getCallback() == null) {
714                 Slogf.w(TAG, "The callback to remove is already dead, do nothing");
715                 return;
716             }
717             if (token.getCallback().asBinder() != callback.asBinder()) {
718                 Slogf.w(TAG, "Cannot remove callback. Provided callback is not the same as the "
719                         + "registered callback for %s", uidName);
720                 return;
721             }
722             callback.asBinder().unlinkToDeath(token, /* flags= */ 0);
723             token.setCallback(null);
724             connection = getServiceConnectionLocked(uidName);
725         }
726         if (connection == null) {
727             Slogf.w(TAG, "No active service connection for uid: %s", uidName);
728             return;
729         }
730         connection.removeAllActiveTasks();
731         Slogf.i(TAG, "All active tasks removed for uid: %s, after %d ms, check whether we should "
732                 + "shutdown", uidName, mTaskUnbindDelayMs);
733         mHandler.postMaybeShutdown(/* delayMs= */ mTaskUnbindDelayMs);
734     }
735 
736     @GuardedBy("mLock")
getUidNameForPackageNameLocked(String packageName)737     private String getUidNameForPackageNameLocked(String packageName) {
738         String uidName = "";
739         try {
740             uidName = getNameForUidLocked(mPackageManager.getPackageUidAsUser(
741                     packageName, PackageInfoFlags.of(0), /* uid= */ 0));
742         } catch (Exception e) {
743             // Do thing.
744         }
745         return uidName;
746     }
747 
748     /**
749      * Used in testing only. Clear up the stored client token information for the package.
750      */
751     @GuardedBy("mLock")
clearUpClientTokenForPackageLocked(String packageName)752     private void clearUpClientTokenForPackageLocked(String packageName) {
753         String uidName = getUidNameForPackageNameLocked(packageName);
754         String clientId = "";
755         for (int i = 0; i < mClientTokenByUidName.size(); i++) {
756             if (!mClientTokenByUidName.keyAt(i).equals(uidName)) {
757                 continue;
758             }
759             clientId = mClientTokenByUidName.valueAt(i).getClientId();
760             break;
761         }
762         if (!clientId.isEmpty()) {
763             Slogf.i(TAG, "Clearing stored client token for uidName: %s because the client is now a "
764                     + "serverless remote task client", uidName);
765             mClientTokenByUidName.remove(uidName);
766             mUidByClientId.remove(clientId);
767         }
768     }
769 
770     /**
771      * {@link android.car.remoteaccess.CarRemoteAccessManager#addServerlessRemoteTaskClient}
772      */
773     @Override
addServerlessRemoteTaskClient(String packageName, String clientId)774     public void addServerlessRemoteTaskClient(String packageName, String clientId) {
775         CarServiceUtils.assertPermission(mContext, Car.PERMISSION_CONTROL_REMOTE_ACCESS);
776         Preconditions.checkArgument(packageName != null, "packageName must not be null");
777         Preconditions.checkArgument(clientId != null, "clientId must not be null");
778         synchronized (mLock) {
779             Slogf.i(TAG, "Adding a new test serverless remote task client, packageName: %s, "
780                     + "clientId: %s", packageName, clientId);
781             if (mServerlessClientIdsByPackageName.containsKey(packageName)) {
782                 String message = "The package: " + packageName
783                         + " is already an serverless remote task client";
784                 Slogf.w(TAG, message);
785                 throw new IllegalArgumentException(message);
786             }
787             for (int i = 0; i < mServerlessClientIdsByPackageName.size(); i++) {
788                 if (mServerlessClientIdsByPackageName.valueAt(i).equals(clientId)) {
789                     String message = "The client ID: " + clientId
790                             + " is already used, pick a different client ID";
791                     Slogf.w(TAG, message);
792                     throw new IllegalArgumentException(message);
793                 }
794             }
795             mServerlessClientIdsByPackageName.put(packageName, clientId);
796             clearUpClientTokenForPackageLocked(packageName);
797         }
798     }
799 
800     /**
801      * {@link android.car.remoteaccess.CarRemoteAccessManager#removeServerlessRemoteTaskClient}
802      */
803     @Override
removeServerlessRemoteTaskClient(String packageName)804     public void removeServerlessRemoteTaskClient(String packageName) {
805         CarServiceUtils.assertPermission(mContext, Car.PERMISSION_CONTROL_REMOTE_ACCESS);
806         Preconditions.checkArgument(packageName != null, "packageName must not be null");
807         synchronized (mLock) {
808             mServerlessClientIdsByPackageName.remove(packageName);
809             clearUpClientTokenForPackageLocked(packageName);
810         }
811     }
812 
813     /**
814      * {@link android.car.remoteaccess.CarRemoteAccessManager#isTaskScheduleSupported}
815      */
816     @Override
isTaskScheduleSupported()817     public boolean isTaskScheduleSupported() {
818         CarServiceUtils.assertPermission(mContext, Car.PERMISSION_CONTROL_REMOTE_ACCESS);
819         if (!mIsHalTaskScheduleSupported) {
820             Slogf.i(TAG, "isTaskScheduleSupported returns false because remote access HAL does not"
821                     + " support task scheduling");
822             return false;
823         }
824         int callingUid = mDep.getCallingUid();
825         String packageName = getPackageNameForCallingUid(callingUid);
826         synchronized (mLock) {
827             if (!mServerlessClientIdsByPackageName.containsKey(packageName)) {
828                 Slogf.i(TAG, "isTaskScheduleSupported returns false the client is not a serverless"
829                         + " remote task client");
830                 return false;
831             }
832         }
833         Slogf.i(TAG, "isTaskScheduleSupported returns true");
834         return true;
835 
836     }
837 
getServerlessCallerClientId()838     private String getServerlessCallerClientId() throws IllegalStateException {
839         if (!mIsHalTaskScheduleSupported) {
840             throw new IllegalStateException("task schedule is not supported by HAL");
841         }
842         int callingUid = mDep.getCallingUid();
843         String packageName = getPackageNameForCallingUid(callingUid);
844         synchronized (mLock) {
845             if (mServerlessClientIdsByPackageName.containsKey(packageName)) {
846                 return mServerlessClientIdsByPackageName.get(packageName);
847             }
848         }
849         throw new IllegalStateException("Caller is not a serverless remote task client");
850     }
851 
852     /**
853      * {@link android.car.remoteaccess.CarRemoteAccessManager#scheduleTask}
854      */
855     @Override
scheduleTask(TaskScheduleInfo scheduleInfo)856     public void scheduleTask(TaskScheduleInfo scheduleInfo) {
857         CarServiceUtils.assertPermission(mContext, Car.PERMISSION_CONTROL_REMOTE_ACCESS);
858         Preconditions.checkArgument(scheduleInfo != null, "scheduleInfo must not be null");
859         Preconditions.checkArgument(scheduleInfo.scheduleId != null, "scheduleId must not be null");
860         Preconditions.checkArgument(scheduleInfo.taskData != null, "task data must not be null");
861         Preconditions.checkArgument(scheduleInfo.count >= 0, "count must >= 0");
862         Preconditions.checkArgument(scheduleInfo.startTimeInEpochSeconds > 0,
863                 "startTimeInEpochSeconds must > 0");
864         Preconditions.checkArgument(scheduleInfo.periodicInSeconds >= 0,
865                 "periodicInSeconds must >= 0");
866         ScheduleInfo halScheduleInfo = new ScheduleInfo();
867         String clientId = getServerlessCallerClientId();
868         halScheduleInfo.clientId = clientId;
869         switch (scheduleInfo.taskType) {
870             case TASK_TYPE_CUSTOM:
871                 halScheduleInfo.taskType = TaskType.CUSTOM;
872                 break;
873             case TASK_TYPE_ENTER_GARAGE_MODE:
874                 halScheduleInfo.taskType = TaskType.ENTER_GARAGE_MODE;
875                 break;
876             default:
877                 throw new IllegalArgumentException("Unsupported task type: "
878                         + scheduleInfo.taskType);
879         }
880         halScheduleInfo.scheduleId = scheduleInfo.scheduleId;
881         halScheduleInfo.taskData = scheduleInfo.taskData;
882         halScheduleInfo.count = scheduleInfo.count;
883         halScheduleInfo.startTimeInEpochSeconds = scheduleInfo.startTimeInEpochSeconds;
884         halScheduleInfo.periodicInSeconds = scheduleInfo.periodicInSeconds;
885         try {
886             mRemoteAccessHalWrapper.scheduleTask(halScheduleInfo);
887         } catch (RemoteException | ServiceSpecificException e) {
888             throw new ServiceSpecificException(SERVICE_ERROR_CODE_GENERAL,
889                     "failed to call IRemoteAccess.scheduleTask with scheduleInfo: "
890                     + halScheduleInfo + ", error: " + e);
891         }
892     }
893 
894     /**
895      * {@link android.car.remoteaccess.CarRemoteAccessManager#unscheduleTask}
896      */
897     @Override
unscheduleTask(String scheduleId)898     public void unscheduleTask(String scheduleId) {
899         CarServiceUtils.assertPermission(mContext, Car.PERMISSION_CONTROL_REMOTE_ACCESS);
900         Preconditions.checkArgument(scheduleId != null, "scheduleId must not be null");
901         String clientId = getServerlessCallerClientId();
902         try {
903             mRemoteAccessHalWrapper.unscheduleTask(clientId, scheduleId);
904         } catch (RemoteException | ServiceSpecificException e) {
905             throw new ServiceSpecificException(SERVICE_ERROR_CODE_GENERAL,
906                     "failed to call IRemoteAccess.unscheduleTask with clientId: "
907                     + clientId + ", scheduleId: " + scheduleId+ ", error: " + e);
908         }
909     }
910 
911     /**
912      * {@link android.car.remoteaccess.CarRemoteAccessManager#unscheduleAllTasks}
913      */
914     @Override
unscheduleAllTasks()915     public void unscheduleAllTasks() {
916         CarServiceUtils.assertPermission(mContext, Car.PERMISSION_CONTROL_REMOTE_ACCESS);
917         String clientId = getServerlessCallerClientId();
918         try {
919             mRemoteAccessHalWrapper.unscheduleAllTasks(clientId);
920         } catch (RemoteException | ServiceSpecificException e) {
921             throw new ServiceSpecificException(SERVICE_ERROR_CODE_GENERAL,
922                     "failed to call IRemoteAccess.unscheduleAllTasks with clientId: "
923                     + clientId + ", error: " + e);
924         }
925     }
926 
927     /**
928      * {@link android.car.remoteaccess.CarRemoteAccessManager#isTaskScheduled}
929      */
930     @Override
isTaskScheduled(String scheduleId)931     public boolean isTaskScheduled(String scheduleId) {
932         CarServiceUtils.assertPermission(mContext, Car.PERMISSION_CONTROL_REMOTE_ACCESS);
933         Preconditions.checkArgument(scheduleId != null, "scheduleId must not be null");
934         String clientId = getServerlessCallerClientId();
935         try {
936             return mRemoteAccessHalWrapper.isTaskScheduled(clientId, scheduleId);
937         } catch (RemoteException | ServiceSpecificException e) {
938             throw new ServiceSpecificException(SERVICE_ERROR_CODE_GENERAL,
939                     "failed to call IRemoteAccess.isTaskScheduled with clientId: "
940                     + clientId + ", scheduleId: " + scheduleId+ ", error: " + e);
941         }
942     }
943 
944     /**
945      * {@link android.car.remoteaccess.CarRemoteAccessManager#getAllPendingScheduledTasks}
946      */
947     @Override
getAllPendingScheduledTasks()948     public List<TaskScheduleInfo> getAllPendingScheduledTasks() {
949         CarServiceUtils.assertPermission(mContext, Car.PERMISSION_CONTROL_REMOTE_ACCESS);
950         String clientId = getServerlessCallerClientId();
951         List<TaskScheduleInfo> taskScheduleInfoList = new ArrayList<>();
952         try {
953             List<ScheduleInfo> halScheduleInfoList =
954                     mRemoteAccessHalWrapper.getAllPendingScheduledTasks(clientId);
955             for (int i = 0; i < halScheduleInfoList.size(); i++) {
956                 ScheduleInfo halScheduleInfo = halScheduleInfoList.get(i);
957                 TaskScheduleInfo taskScheduleInfo = new TaskScheduleInfo();
958                 taskScheduleInfo.scheduleId = halScheduleInfo.scheduleId;
959                 taskScheduleInfo.taskData = halScheduleInfo.taskData;
960                 taskScheduleInfo.count = halScheduleInfo.count;
961                 taskScheduleInfo.startTimeInEpochSeconds = halScheduleInfo.startTimeInEpochSeconds;
962                 taskScheduleInfo.periodicInSeconds = halScheduleInfo.periodicInSeconds;
963                 switch (halScheduleInfo.taskType) {
964                     case TaskType.CUSTOM:
965                         taskScheduleInfo.taskType = TASK_TYPE_CUSTOM;
966                         break;
967                     case TaskType.ENTER_GARAGE_MODE:
968                         taskScheduleInfo.taskType = TASK_TYPE_ENTER_GARAGE_MODE;
969                         break;
970                     default:
971                         Slogf.e(TAG, "Unknown task type returned by remote access HAL for: "
972                                 + taskScheduleInfo + ", default to TASK_TYPE_CUSTOM");
973                         taskScheduleInfo.taskType = TASK_TYPE_CUSTOM;
974                 }
975                 taskScheduleInfoList.add(taskScheduleInfo);
976             }
977             return taskScheduleInfoList;
978         } catch (RemoteException | ServiceSpecificException e) {
979             throw new ServiceSpecificException(SERVICE_ERROR_CODE_GENERAL,
980                     "failed to call IRemoteAccess.getAllPendingScheduledTasks with clientId: "
981                     + clientId + ", error: " + e);
982         }
983     }
984 
985     @Override
getSupportedTaskTypesForScheduling()986     public int[] getSupportedTaskTypesForScheduling() {
987         if (!isTaskScheduleSupported()) {
988             Slogf.i(TAG, "task scheduling is not supported, return empty array for "
989                     + "getSupportedTaskTypesForScheduling");
990             return EMPTY_INT_ARRAY;
991         }
992         int[] supportedHalTaskTypes;
993         try {
994             supportedHalTaskTypes = mRemoteAccessHalWrapper.getSupportedTaskTypesForScheduling();
995         } catch (RemoteException | ServiceSpecificException e) {
996             throw new ServiceSpecificException(SERVICE_ERROR_CODE_GENERAL,
997                     "failed to call IRemoteAccess.getSupportedTaskTypesForScheduling, error: " + e);
998         }
999         ArraySet<Integer> supportedMgrTaskTypes = new ArraySet<>();
1000         for (int i = 0; i < supportedHalTaskTypes.length; i++) {
1001             switch (supportedHalTaskTypes[i]) {
1002                 case TaskType.CUSTOM:
1003                     supportedMgrTaskTypes.add(TASK_TYPE_CUSTOM);
1004                     break;
1005                 case TaskType.ENTER_GARAGE_MODE:
1006                     supportedMgrTaskTypes.add(TASK_TYPE_ENTER_GARAGE_MODE);
1007                     break;
1008                 default:
1009                     Slogf.e(TAG, "Unknown supported task type returned from remote access HAL, "
1010                             + "ignore: " + supportedHalTaskTypes[i]);
1011             }
1012         }
1013         // Convert to int array.
1014         int[] result = new int[supportedMgrTaskTypes.size()];
1015         for (int i = 0; i < supportedMgrTaskTypes.size(); i++) {
1016             result[i] = supportedMgrTaskTypes.valueAt(i);
1017         }
1018         return result;
1019     }
1020 
1021     @GuardedBy("mLock")
getTokenForUidNameAndCheckClientIdLocked(String uidName, String clientId)1022     private ClientToken getTokenForUidNameAndCheckClientIdLocked(String uidName, String clientId)
1023             throws IllegalArgumentException {
1024         ClientToken token = mClientTokenByUidName.get(uidName);
1025         if (token == null) {
1026             throw new IllegalArgumentException("Callback has not been registered");
1027         }
1028         // TODO(b/252698817): Update the validity checking logic.
1029         if (!clientId.equals(token.getClientId())) {
1030             throw new IllegalArgumentException("Client ID(" + clientId + ") doesn't match the "
1031                     + "registered one(" + token.getClientId() + ")");
1032         }
1033         return token;
1034     }
1035 
1036     @GuardedBy("mLock")
getServiceConnectionLocked(String uidName)1037     private @Nullable RemoteTaskClientServiceConnection getServiceConnectionLocked(String uidName) {
1038         if (DEBUG) {
1039             Slogf.d(TAG, "getServiceConnectionLocked for uid: %s", uidName);
1040         }
1041         RemoteTaskClientServiceInfo serviceInfo = mClientServiceInfoByUid.get(uidName);
1042         if (serviceInfo == null) {
1043             if (DEBUG) {
1044                 Slogf.d(TAG, "the service info for uid: %s is null", uidName);
1045             }
1046             return null;
1047         }
1048         return serviceInfo.getServiceConnection();
1049     }
1050 
1051     /**
1052      * Reports that the task of {@code taskId} is completed.
1053      *
1054      * @param clientId ID of a client that has completed the task.
1055      * @param taskId ID of a task that has been completed.
1056      * @throws IllegalArgumentException When {@code clientId} is not valid, or {@code taskId} is not
1057      *         valid.
1058      */
1059     @Override
reportRemoteTaskDone(String clientId, String taskId)1060     public void reportRemoteTaskDone(String clientId, String taskId) {
1061         Slogf.i(TAG, "reportRemoteTaskDone for client: %s, task: %s", clientId, taskId);
1062         CarServiceUtils.assertPermission(mContext, Car.PERMISSION_USE_REMOTE_ACCESS);
1063         Preconditions.checkArgument(clientId != null, "clientId cannot be null");
1064         Preconditions.checkArgument(taskId != null, "taskId cannot be null");
1065         int callingUid = mDep.getCallingUid();
1066         String uidName;
1067         RemoteTaskClientServiceConnection serviceConnection;
1068         synchronized (mLock) {
1069             uidName = getNameForUidLocked(callingUid);
1070             getTokenForUidNameAndCheckClientIdLocked(uidName, clientId);
1071             serviceConnection = getServiceConnectionLocked(uidName);
1072         }
1073         if (serviceConnection == null) {
1074             throw new IllegalArgumentException("No active service connection, uidName: " + uidName
1075                     + ", clientId: " + clientId);
1076         }
1077         if (!serviceConnection.removeActiveTasks(new ArraySet<>(Set.of(taskId)))) {
1078             throw new IllegalArgumentException("Task ID(" + taskId + ") is not valid");
1079         }
1080         if (DEBUG) {
1081             Slogf.d(TAG, "Task: %s complete, after %d ms, check whether we should shutdown",
1082                     taskId, mTaskUnbindDelayMs);
1083         }
1084         mHandler.postMaybeShutdown(/* delayMs= */ mTaskUnbindDelayMs);
1085     }
1086 
1087     @Override
setPowerStatePostTaskExecution(int nextPowerState, boolean runGarageMode)1088     public void setPowerStatePostTaskExecution(int nextPowerState, boolean runGarageMode) {
1089         CarServiceUtils.assertPermission(mContext, Car.PERMISSION_CONTROL_REMOTE_ACCESS);
1090         Slogf.i(TAG, "setPowerStatePostTaskExecution, nextPowerState: %d, runGarageMode: %B",
1091                 nextPowerState, runGarageMode);
1092 
1093         synchronized (mLock) {
1094             mNextPowerState = nextPowerState;
1095             mRunGarageMode = runGarageMode;
1096         }
1097     }
1098 
1099     @Override
confirmReadyForShutdown(String clientId)1100     public void confirmReadyForShutdown(String clientId) {
1101         CarServiceUtils.assertPermission(mContext, Car.PERMISSION_USE_REMOTE_ACCESS);
1102         Preconditions.checkArgument(clientId != null, "clientId cannot be null");
1103         int callingUid = mDep.getCallingUid();
1104         boolean isAllClientReadyForShutDown = true;
1105         synchronized (mLock) {
1106             String uidName = getNameForUidLocked(callingUid);
1107             Slogf.i(TAG, "confirmReadyForShutdown from client: %s, uidName: %s", clientId, uidName);
1108             ClientToken token = getTokenForUidNameAndCheckClientIdLocked(uidName, clientId);
1109             token.setIsReadyForShutdown();
1110 
1111             for (int i = 0; i < mClientTokenByUidName.size(); i++) {
1112                 ClientToken clientToken = mClientTokenByUidName.valueAt(i);
1113                 if (clientToken.getCallback() == null) {
1114                     continue;
1115                 }
1116                 if (!clientToken.isReadyForShutdown()) {
1117                     isAllClientReadyForShutDown = false;
1118                 }
1119             }
1120         }
1121 
1122         if (isAllClientReadyForShutDown) {
1123             mHandler.postWrapUpRemoteAccessService(/* delayMs= */ 0);
1124         }
1125     }
1126 
1127     /**
1128      * Returns whether {@code VEHICLE_IN_USE} is supported and getting it returns a valid value.
1129      */
1130     @Override
isVehicleInUseSupported()1131     public boolean isVehicleInUseSupported() {
1132         CarServiceUtils.assertPermission(mContext, Car.PERMISSION_CONTROL_REMOTE_ACCESS);
1133         return mPowerHalService.isVehicleInUseSupported();
1134     }
1135 
1136     /**
1137      * Returns whether {@code SHUTDOWN_REQUEST} is supported.
1138      */
1139     @Override
isShutdownRequestSupported()1140     public boolean isShutdownRequestSupported() {
1141         CarServiceUtils.assertPermission(mContext, Car.PERMISSION_CONTROL_REMOTE_ACCESS);
1142         return mPowerHalService.isShutdownRequestSupported();
1143     }
1144 
1145     @VisibleForTesting
getRemoteAccessHalCallback()1146     RemoteAccessHalCallback getRemoteAccessHalCallback() {
1147         return mHalCallback;
1148     }
1149 
1150     @VisibleForTesting
getAllowedSystemUptimeMs()1151     long getAllowedSystemUptimeMs() {
1152         return mAllowedSystemUptimeMs;
1153     }
1154 
1155     @VisibleForTesting
getServerlessClientIdsByPackageName()1156     ArrayMap<String, String> getServerlessClientIdsByPackageName() {
1157         synchronized (mLock) {
1158             return mServerlessClientIdsByPackageName;
1159         }
1160     }
1161 
parseServerlessClientIdsByPackageName()1162     private ArrayMap<String, String> parseServerlessClientIdsByPackageName() {
1163         ArrayMap<String, String> clientIdsByPackageName = new ArrayMap<>();
1164 
1165         if (!mFeatureFlags.serverlessRemoteAccess()) {
1166             Slogf.i(TAG, "Serverless remote access flag is disabled, skip parsing "
1167                     + "remote_access_serverless_client_map.xml");
1168             return clientIdsByPackageName;
1169         }
1170 
1171         try (XmlResourceParser parser = mContext.getResources().getXml(
1172                 R.xml.remote_access_serverless_client_map)) {
1173             // Get to the first start tag.
1174             while (parser.getEventType() != XmlPullParser.START_TAG) {
1175                 if (parser.next() == XmlPullParser.END_DOCUMENT) {
1176                     break;
1177                 }
1178             }
1179 
1180             // Check the root tag.
1181             parser.require(XmlPullParser.START_TAG, /* namespace= */ null,
1182                     XML_TAG_SERVERLESS_CLIENT_MAP);
1183             while (parser.next() != XmlPullParser.END_DOCUMENT) {
1184                 if (parser.getEventType() != XmlPullParser.START_TAG) {
1185                     continue;
1186                 }
1187                 String name = parser.getName();
1188                 if (name.equals(XML_TAG_SERVERLESS_CLIENT)) {
1189                     readServerlessClient(parser, clientIdsByPackageName);
1190                 } else {
1191                     skip(parser);
1192                 }
1193             }
1194         } catch (Exception e) {
1195             Slogf.e(TAG, "Failed to parse remote_access_serverless_client_map.xml, disabled all "
1196                     + "serverless remote task client.", e);
1197         }
1198 
1199         return clientIdsByPackageName;
1200     }
1201 
readServerlessClient(XmlPullParser parser, ArrayMap<String, String> clientIdsByPackageName)1202     private void readServerlessClient(XmlPullParser parser,
1203             ArrayMap<String, String> clientIdsByPackageName)
1204             throws XmlPullParserException, IOException {
1205         parser.require(XmlPullParser.START_TAG, /* namespace= */ null, XML_TAG_SERVERLESS_CLIENT);
1206         String clientId = null;
1207         String packageName = null;
1208         while (parser.next() != XmlPullParser.END_TAG) {
1209             if (parser.getEventType() != XmlPullParser.START_TAG) {
1210                 continue;
1211             }
1212             String name = parser.getName();
1213             if (name.equals(XML_TAG_CLIENT_ID)) {
1214                 clientId = readClientId(parser);
1215             } else if (name.equals(XML_TAG_PACKAGE_NAME)) {
1216                 packageName = readPackageName(parser);
1217             } else {
1218                 skip(parser);
1219             }
1220         }
1221         if (clientId == null) {
1222             throw new IllegalStateException("Missing ClientId field");
1223         }
1224         if (packageName == null) {
1225             throw new IllegalStateException("Missing PackageName field");
1226         }
1227         clientIdsByPackageName.put(packageName, clientId);
1228     }
1229 
readClientId(XmlPullParser parser)1230     private String readClientId(XmlPullParser parser)
1231             throws XmlPullParserException, IOException {
1232         parser.require(XmlPullParser.START_TAG, /* namespace= */ null, XML_TAG_CLIENT_ID);
1233         String clientId = readText(parser);
1234         parser.require(XmlPullParser.END_TAG, /* namespace= */ null, XML_TAG_CLIENT_ID);
1235         return clientId;
1236     }
1237 
readPackageName(XmlPullParser parser)1238     private String readPackageName(XmlPullParser parser)
1239             throws XmlPullParserException, IOException  {
1240         parser.require(XmlPullParser.START_TAG, /* namespace= */ null, XML_TAG_PACKAGE_NAME);
1241         String packageName = readText(parser);
1242         parser.require(XmlPullParser.END_TAG, /* namespace= */ null, XML_TAG_PACKAGE_NAME);
1243         return packageName;
1244     }
1245 
1246     // For the tags title and summary, extracts their text values.
readText(XmlPullParser parser)1247     private String readText(XmlPullParser parser) throws IOException, XmlPullParserException {
1248         String result = "";
1249         if (parser.next() == XmlPullParser.TEXT) {
1250             result = parser.getText();
1251             parser.nextTag();
1252         }
1253         return result;
1254     }
1255 
1256     // Skip uninterested tags.
skip(XmlPullParser parser)1257     private void skip(XmlPullParser parser) throws XmlPullParserException, IOException {
1258         if (parser.getEventType() != XmlPullParser.START_TAG) {
1259             throw new IllegalStateException("Invalid xml");
1260         }
1261         int depth = 1;
1262         while (depth != 0) {
1263             switch (parser.next()) {
1264                 case XmlPullParser.END_TAG:
1265                     depth--;
1266                     break;
1267                 case XmlPullParser.START_TAG:
1268                     depth++;
1269                     break;
1270             }
1271         }
1272     }
1273 
populatePackageClientIdMapping()1274     private void populatePackageClientIdMapping() {
1275         List<ClientIdEntry> clientIdEntries = mRemoteAccessStorage.getClientIdEntries();
1276         ArrayMap<String, String> clientIdsByPackageName = parseServerlessClientIdsByPackageName();
1277 
1278         synchronized (mLock) {
1279             if (clientIdEntries != null) {
1280                 for (int i = 0; i < clientIdEntries.size(); i++) {
1281                     ClientIdEntry entry = clientIdEntries.get(i);
1282                     mUidByClientId.put(entry.clientId, entry.uidName);
1283                     mClientTokenByUidName.put(entry.uidName,
1284                             new ClientToken(entry.clientId, entry.idCreationTime));
1285                 }
1286             }
1287             mServerlessClientIdsByPackageName = clientIdsByPackageName;
1288             Slogf.i(TAG, "mServerlessClientIdsByPackageName: " + clientIdsByPackageName);
1289         }
1290     }
1291 
saveClientIdInDb(ClientToken token, String uidName)1292     private void saveClientIdInDb(ClientToken token, String uidName) {
1293         if (token.isServerless()) {
1294             // This token is static and no need to be stored in db.
1295             return;
1296         }
1297         ClientIdEntry entry = new ClientIdEntry(token.getClientId(), token.getIdCreationTime(),
1298                 uidName);
1299         if (!mRemoteAccessStorage.updateClientId(entry)) {
1300             Slogf.e(TAG, "Failed to save %s for %s in the database", token, uidName);
1301         }
1302     }
1303 
postRegistrationUpdated(ICarRemoteAccessCallback callback, ClientToken token)1304     private void postRegistrationUpdated(ICarRemoteAccessCallback callback, ClientToken token) {
1305         String clientId = token.getClientId();
1306         mHandler.post(() -> {
1307             if (DEBUG) {
1308                 Slogf.d(TAG, "Calling onClientRegistrationUpdated: serviceName=%s, "
1309                         + "vehicleId=%s, processorId=%s, clientId=%s, isServerless=%s",
1310                         mWakeupServiceName, mVehicleId, mProcessorId, clientId,
1311                         token.isServerless());
1312             }
1313             if (!token.isServerless()) {
1314                 try {
1315                     callback.onClientRegistrationUpdated(new RemoteTaskClientRegistrationInfo(
1316                             mWakeupServiceName, mVehicleId, mProcessorId, clientId));
1317                 } catch (RemoteException e) {
1318                     Slogf.e(TAG, e, "Calling onClientRegistrationUpdated() failed: clientId = %s",
1319                             clientId);
1320                 }
1321             } else {
1322                 try {
1323                     callback.onServerlessClientRegistered(clientId);
1324                 } catch (RemoteException e) {
1325                     Slogf.e(TAG, e, "Calling onServerlessClientRegistered() failed");
1326                 }
1327             }
1328 
1329             // After notify the client about the registration info, the callback is registered.
1330             token.setCallback(callback);
1331 
1332             // Just after a registration callback is invoked, let's call onRemoteTaskRequested
1333             // callback if there are pending tasks.
1334             maybeStartNewRemoteTask(clientId);
1335         });
1336     }
1337 
shutdownIfNeeded(boolean force)1338     private void shutdownIfNeeded(boolean force) {
1339         if (DEBUG) {
1340             Slogf.d(TAG, "shutdownIfNeeded, force: %B", force);
1341         }
1342         int nextPowerState;
1343         boolean runGarageMode;
1344         synchronized (mLock) {
1345             if (mNextPowerState == CarRemoteAccessManager.NEXT_POWER_STATE_ON) {
1346                 Slogf.i(TAG, "Will not shutdown. The next power state is ON.");
1347                 return;
1348             }
1349             if (mPowerHalService.isVehicleInUse()) {
1350                 Slogf.i(TAG, "Will not shutdown. The vehicle is in use.");
1351                 return;
1352             }
1353             int taskCount = getActiveTaskCountLocked();
1354             if (!force && taskCount > 0) {
1355                 Slogf.i(TAG, "Will not shutdown. The activen task count is %d.", taskCount);
1356                 return;
1357             }
1358             nextPowerState = mNextPowerState;
1359             runGarageMode = mRunGarageMode;
1360         }
1361         if (DEBUG) {
1362             Slogf.d(TAG, "unbindAllServices before shutdown");
1363         }
1364         unbindAllServices();
1365         // Send SHUTDOWN_REQUEST to VHAL.
1366         Slogf.i(TAG, "Requesting shutdown of AP: nextPowerState = %d, runGarageMode = %b",
1367                 nextPowerState, runGarageMode);
1368         try {
1369             mPowerService.requestShutdownAp(nextPowerState, runGarageMode);
1370         } catch (Exception e) {
1371             Slogf.e(TAG, e, "Cannot shutdown to %s", nextPowerStateToString(nextPowerState));
1372         }
1373     }
1374 
1375     /**
1376      * Unbinds all the remote task client services.
1377      */
unbindAllServices()1378     public void unbindAllServices() {
1379         Slogf.i(TAG, "unbind all the remote task client services");
1380         ArrayMap<String, RemoteTaskClientServiceInfo> clientServiceInfoByUid;
1381         synchronized (mLock) {
1382             clientServiceInfoByUid = new ArrayMap<>(mClientServiceInfoByUid);
1383         }
1384         for (int i = 0; i < clientServiceInfoByUid.size(); i++) {
1385             unbindRemoteTaskClientService(clientServiceInfoByUid.valueAt(i),
1386                     /* force= */ true);
1387         }
1388     }
1389 
1390     @GuardedBy("mLock")
calcTaskMaxDurationInMsLocked()1391     private long calcTaskMaxDurationInMsLocked() {
1392         long taskMaxDurationInMs;
1393         if (mNextPowerState == CarRemoteAccessManager.NEXT_POWER_STATE_ON
1394                 || mPowerHalService.isVehicleInUse()) {
1395             // If next power state is ON or vehicle is in use, the mShutdownTimeInMs does not make
1396             // sense because shutdown will not happen. We always allow task to execute for
1397             // mAllowedSystemUptimMs.
1398             taskMaxDurationInMs = mAllowedSystemUptimeMs;
1399         } else {
1400             taskMaxDurationInMs = mShutdownTimeInMs - SystemClock.uptimeMillis();
1401         }
1402         if (DEBUG) {
1403             Slogf.d(TAG, "Task max duration in ms: %d", taskMaxDurationInMs);
1404         }
1405         return taskMaxDurationInMs;
1406     }
1407 
1408     @VisibleForTesting
getActiveTaskCount()1409     int getActiveTaskCount() {
1410         synchronized (mLock) {
1411             return getActiveTaskCountLocked();
1412         }
1413     }
1414 
1415     @GuardedBy("mLock")
getActiveTaskCountLocked()1416     private int getActiveTaskCountLocked() {
1417         int count = 0;
1418         for (int i = 0; i < mClientServiceInfoByUid.size(); i++) {
1419             RemoteTaskClientServiceInfo serviceInfo = mClientServiceInfoByUid.valueAt(i);
1420             if (serviceInfo.getServiceConnection() != null) {
1421                 count += serviceInfo.getServiceConnection().getActiveTaskCount();
1422             }
1423         }
1424         return count;
1425     }
1426 
getLastShutdownState()1427     private int getLastShutdownState() {
1428         return mPowerService.getLastShutdownState();
1429     }
1430 
getAllowedSystemUptimeForRemoteTaskInMs()1431     private long getAllowedSystemUptimeForRemoteTaskInMs() {
1432         long timeout = mContext.getResources()
1433                 .getInteger(R.integer.config_allowedSystemUptimeForRemoteAccess);
1434         if (timeout < MIN_SYSTEM_UPTIME_FOR_REMOTE_ACCESS_IN_SEC) {
1435             timeout = MIN_SYSTEM_UPTIME_FOR_REMOTE_ACCESS_IN_SEC;
1436             Slogf.w(TAG, "config_allowedSystemUptimeForRemoteAccess(%d) should be no less than %d",
1437                     timeout, MIN_SYSTEM_UPTIME_FOR_REMOTE_ACCESS_IN_SEC);
1438         }
1439         return timeout * MILLI_TO_SECOND;
1440     }
1441 
getNotifyApStateChangeRetrySleepInMs()1442     private int getNotifyApStateChangeRetrySleepInMs() {
1443         int notifyApStateChangeRetrySleepInMs = mContext.getResources()
1444                 .getInteger(R.integer.config_notifyApStateChange_retry_sleep_ms);
1445         if (notifyApStateChangeRetrySleepInMs < 0) {
1446             Slogf.e(TAG, "Invalid config_notifyApStateChange_retry_sleep_ms from RRO: "
1447                     + notifyApStateChangeRetrySleepInMs + ", must be a positive integer");
1448             notifyApStateChangeRetrySleepInMs = DEFAULT_NOTIFY_AP_STATE_RETRY_SLEEP_IN_MS;
1449         }
1450         return notifyApStateChangeRetrySleepInMs;
1451     }
1452 
getNotifyApStateChangeMaxRetry()1453     private int getNotifyApStateChangeMaxRetry() {
1454         int notifyApStateChangeMaxRetry = mContext.getResources()
1455                 .getInteger(R.integer.config_notifyApStateChange_max_retry);
1456         if (notifyApStateChangeMaxRetry < 0) {
1457             Slogf.e(TAG, "Invalid config_notifyApStateChange_max_retry from RRO: "
1458                     + notifyApStateChangeMaxRetry + ", must be a positive integer");
1459             notifyApStateChangeMaxRetry = DEFAULT_NOTIFY_AP_STATE_MAX_RETRY;
1460         }
1461         return notifyApStateChangeMaxRetry;
1462     }
1463 
1464     // Gets the UID name for the specified UID. Read from a cached map if exists. Uses package
1465     // manager to get UID if it does not exist in cached map.
1466     @GuardedBy("mLock")
getNameForUidLocked(int uid)1467     private String getNameForUidLocked(int uid) {
1468         String uidName = mNameByUid.get(uid);
1469         if (uidName != null) {
1470             return uidName;
1471         }
1472         uidName = mPackageManager.getNameForUid(uid);
1473         mUidByName.put(uidName, uid);
1474         mNameByUid.put(uid, uidName);
1475         return uidName;
1476     }
1477 
1478     // Searchs for all remote task client service packages accroding to the declared intent and
1479     // filter them according to their permissions.
1480     // This will start the found remote task client services (as system user) for init registration.
searchForRemoteTaskClientPackages()1481     private void searchForRemoteTaskClientPackages() {
1482         // TODO(b/266129982): Query for all users.
1483         if (DEBUG) {
1484             Slogf.d(TAG, "searchForRemoteTaskClientPackages");
1485         }
1486         List<ResolveInfo> services = mPackageManager.queryIntentServicesAsUser(
1487                 new Intent(Car.CAR_REMOTEACCESS_REMOTE_TASK_CLIENT_SERVICE), /* flags= */ 0,
1488                 UserHandle.SYSTEM);
1489         ArrayMap<String, RemoteTaskClientServiceInfo> serviceInfoByUidName = new ArrayMap<>();
1490         synchronized (mLock) {
1491             for (int i = 0; i < services.size(); i++) {
1492                 ServiceInfo info = services.get(i).serviceInfo;
1493                 String packageName = info.packageName;
1494                 ComponentName componentName = new ComponentName(packageName, info.name);
1495                 // We require client to has PERMISSION_CONTROL_REMOTE_ACCESS which is a system API
1496                 // so that they can be launched as system user.
1497                 if (mPackageManager.checkPermission(Car.PERMISSION_CONTROL_REMOTE_ACCESS,
1498                         packageName) != PackageManager.PERMISSION_GRANTED) {
1499                     Slogf.w(TAG, "Component(%s) has %s intent but doesn't have %s permission",
1500                             componentName.flattenToString(),
1501                             Car.CAR_REMOTEACCESS_REMOTE_TASK_CLIENT_SERVICE,
1502                             Car.PERMISSION_CONTROL_REMOTE_ACCESS);
1503                     continue;
1504                 }
1505                 // TODO(b/263798644): mClientServiceInfoByUid should be updated when packages
1506                 // are added, removed, updated.
1507                 RemoteTaskClientServiceInfo serviceInfo =
1508                         new RemoteTaskClientServiceInfo(componentName);
1509                 String uidName = getNameForUidLocked(info.applicationInfo.uid);
1510                 mClientServiceInfoByUid.put(uidName, serviceInfo);
1511                 if (DEBUG) {
1512                     Slogf.d(TAG, "Package(%s) is found as a remote task client service",
1513                             packageName);
1514                 }
1515                 // Store the service info to be started later outside the lock.
1516                 serviceInfoByUidName.put(uidName, serviceInfo);
1517             }
1518         }
1519         // Start the remote task client services outside the lock since binding might be a slow
1520         // operation.
1521         for (int i = 0; i < serviceInfoByUidName.size(); i++) {
1522             startRemoteTaskClientService(serviceInfoByUidName.valueAt(i),
1523                     serviceInfoByUidName.keyAt(i), mAllowedTimeForRemoteTaskClientInitMs);
1524         }
1525     }
1526 
1527     // Starts the remote task client service if not already started and extends its liftime.
startRemoteTaskClientService(RemoteTaskClientServiceInfo serviceInfo, String uidName, long taskDurationMs)1528     private void startRemoteTaskClientService(RemoteTaskClientServiceInfo serviceInfo,
1529             String uidName, long taskDurationMs) {
1530         ComponentName serviceName = serviceInfo.getServiceComponentName();
1531 
1532         // Critical section to protect modification to serviceInfo.
1533         RemoteTaskClientServiceConnection serviceConnection;
1534         synchronized (mLock) {
1535             // TODO(b/266129982): Start a service for the user under which the task needs to be
1536             // executed.
1537             if (serviceInfo.getServiceConnection() != null) {
1538                 serviceConnection = serviceInfo.getServiceConnection();
1539             } else {
1540                 int uid = mUidByName.get(uidName);
1541                 serviceConnection = new RemoteTaskClientServiceConnection(mContext, mHandler,
1542                         mUserManager, serviceName, UserHandle.SYSTEM, uid, mTaskUnbindDelayMs);
1543                 serviceInfo.setServiceConnection(serviceConnection);
1544             }
1545         }
1546         long taskTimeoutMs = SystemClock.uptimeMillis() + taskDurationMs;
1547         Slogf.i(TAG, "Service(%s) is bound to give a time to register as a remote task client",
1548                 serviceName.flattenToString());
1549 
1550         serviceConnection.bindServiceAndExtendTaskTimeoutMs(taskTimeoutMs);
1551     }
1552 
onServiceTimeout(int uid)1553     private void onServiceTimeout(int uid) {
1554         RemoteTaskClientServiceInfo serviceInfo;
1555         synchronized (mLock) {
1556             String uidName = getNameForUidLocked(uid);
1557             serviceInfo = mClientServiceInfoByUid.get(uidName);
1558             if (serviceInfo == null) {
1559                 Slogf.e(TAG, "No service connection info for %s, must not happen", uidName);
1560                 return;
1561             }
1562         }
1563         Slogf.w(TAG, "The service: %s timeout, clearing all pending tasks and "
1564                 + "unbind", serviceInfo.getServiceComponentName());
1565         unbindRemoteTaskClientService(serviceInfo, /* force= */ false);
1566     }
1567 
1568     // Stops the remote task client service. If {@code force} is true, the service will always be
1569     // unbound if it is binding or already bound. If it is false, the service will be unbound if
1570     // the service passed its liftime.
unbindRemoteTaskClientService(RemoteTaskClientServiceInfo serviceInfo, boolean force)1571     private void unbindRemoteTaskClientService(RemoteTaskClientServiceInfo serviceInfo,
1572             boolean force) {
1573         if (DEBUG) {
1574             Slogf.d(TAG, "Unbinding remote task client service, force: %B", force);
1575         }
1576         RemoteTaskClientServiceConnection connection = serviceInfo.getServiceConnection();
1577         if (connection == null) {
1578             Slogf.w(TAG, "Cannot unbind remote task client service: no service connection");
1579             return;
1580         }
1581         ComponentName serviceName = serviceInfo.getServiceComponentName();
1582         if (connection.unbindService(force)) {
1583             Slogf.i(TAG, "Service(%s) is unbound from CarRemoteAccessService", serviceName);
1584         } else {
1585             Slogf.w(TAG, "Failed to unbind remote task client service(%s)", serviceName);
1586         }
1587     }
1588 
notifyApStateChange()1589     private void notifyApStateChange() {
1590         if (DEBUG) {
1591             Slogf.d(TAG, "notify ap state change");
1592         }
1593         boolean isReadyForRemoteTask;
1594         boolean isWakeupRequired;
1595         synchronized (mLock) {
1596             isReadyForRemoteTask = mIsReadyForRemoteTask;
1597             isWakeupRequired = mIsWakeupRequired;
1598             mNotifyApStateChangeRetryCount++;
1599             if (mNotifyApStateChangeRetryCount > mNotifyApStateChangeMaxRetry) {
1600                 Slogf.e(TAG, "Reached max retry count for trying to notify AP state change, "
1601                         + "Failed to notify AP state Change!!!");
1602                 return;
1603             }
1604         }
1605         if (!mRemoteAccessHalWrapper.notifyApStateChange(isReadyForRemoteTask, isWakeupRequired)) {
1606             Slogf.e(TAG, "Cannot notify AP state change, waiting for "
1607                     + mNotifyApStateChangeRetrySleepInMs + "ms and retry");
1608             mHandler.postNotifyApStateChange(mNotifyApStateChangeRetrySleepInMs);
1609             return;
1610         }
1611         synchronized (mLock) {
1612             mNotifyApStateChangeRetryCount = 0;
1613         }
1614         if (DEBUG) {
1615             Slogf.d(TAG, "Notified AP about new state, isReadyForRemoteTask: %B, "
1616                     + "isWakeupRequired: %B", isReadyForRemoteTask, isWakeupRequired);
1617         }
1618     }
1619 
notifyShutdownStarting()1620     private void notifyShutdownStarting() {
1621         List<ICarRemoteAccessCallback> callbacks = new ArrayList<>();
1622         Slogf.i(TAG, "notifyShutdownStarting");
1623         synchronized (mLock) {
1624             if (mNextPowerState == CarRemoteAccessManager.NEXT_POWER_STATE_ON) {
1625                 Slogf.i(TAG, "Skipping notifyShutdownStarting because the next power state is ON");
1626                 return;
1627             }
1628             if (mPowerHalService.isVehicleInUse()) {
1629                 Slogf.i(TAG, "Skipping notifyShutdownStarting because vehicle is currently in use");
1630                 return;
1631             }
1632             for (int i = 0; i < mClientTokenByUidName.size(); i++) {
1633                 ClientToken token = mClientTokenByUidName.valueAt(i);
1634                 if (token.getCallback() == null) {
1635                     Slogf.w(TAG, "Notifying client(%s) of shutdownStarting is skipped: invalid "
1636                             + "client token", token);
1637                     continue;
1638                 }
1639                 callbacks.add(token.getCallback());
1640             }
1641         }
1642         for (int i = 0; i < callbacks.size(); i++) {
1643             ICarRemoteAccessCallback callback = callbacks.get(i);
1644             try {
1645                 callback.onShutdownStarting();
1646             } catch (RemoteException e) {
1647                 Slogf.e(TAG, "Calling onShutdownStarting() failed: package", e);
1648             }
1649         }
1650     }
1651 
wrapUpRemoteAccessServiceIfNeeded()1652     private void wrapUpRemoteAccessServiceIfNeeded() {
1653         synchronized (mLock) {
1654             if (mNextPowerState != CarRemoteAccessManager.NEXT_POWER_STATE_ON
1655                     && !mPowerHalService.isVehicleInUse()) {
1656                 Slogf.i(TAG, "Remote task execution time has expired: wrapping up the service");
1657             }
1658         }
1659         shutdownIfNeeded(/* force= */ true);
1660     }
1661 
1662     @Nullable
getRemoteTaskClientServiceInfo(String clientId)1663     RemoteTaskClientServiceInfo getRemoteTaskClientServiceInfo(String clientId) {
1664         synchronized (mLock) {
1665             String uidName = mUidByClientId.get(clientId);
1666             if (uidName == null) {
1667                 Slogf.w(TAG, "Cannot get package name for client ID(%s)", clientId);
1668                 return null;
1669             }
1670             return mClientServiceInfoByUid.get(uidName);
1671         }
1672     }
1673 
invokeTaskRequestCallbacks(RemoteTaskClientServiceConnection serviceConnection, ICarRemoteAccessCallback callback, String clientId, List<RemoteTask> tasks, int taskMaxDurationInSec)1674     private void invokeTaskRequestCallbacks(RemoteTaskClientServiceConnection serviceConnection,
1675             ICarRemoteAccessCallback callback, String clientId, List<RemoteTask> tasks,
1676             int taskMaxDurationInSec) {
1677         ArraySet<String> taskIds = new ArraySet<>();
1678         for (int i = 0; i < tasks.size(); i++) {
1679             taskIds.add(tasks.get(i).id);
1680         }
1681         serviceConnection.addActiveTasks(taskIds);
1682 
1683         ArraySet<String> failedTaskIds = new ArraySet<>();
1684         for (int i = 0; i < tasks.size(); i++) {
1685             RemoteTask task = tasks.get(i);
1686             try {
1687                 Slogf.i(TAG, "Delivering remote task, clientId: %s, taskId: %s, "
1688                         + "max duration: %d sec", clientId, task.id, taskMaxDurationInSec);
1689                 callback.onRemoteTaskRequested(clientId, task.id, task.data, taskMaxDurationInSec);
1690             } catch (RemoteException e) {
1691                 Slogf.e(TAG, e, "Calling onRemoteTaskRequested() failed: clientId = %s, "
1692                         + "taskId = %s, data size = %d, taskMaxDurationInSec = %d", clientId,
1693                         task.id, task.data != null ? task.data.length : 0, taskMaxDurationInSec);
1694                 failedTaskIds.add(task.id);
1695             }
1696         }
1697         if (!failedTaskIds.isEmpty()) {
1698             serviceConnection.removeActiveTasks(failedTaskIds);
1699         }
1700     }
1701 
1702     @GuardedBy("mLock")
pushTaskToPendingQueueLocked(String clientId, RemoteTask task)1703     private void pushTaskToPendingQueueLocked(String clientId, RemoteTask task) {
1704         if (DEBUG) {
1705             Slogf.d(TAG, "received a new remote task: %s", task);
1706         }
1707 
1708         ArrayList remoteTasks = mTasksToBeNotifiedByClientId.get(clientId);
1709         if (remoteTasks == null) {
1710             remoteTasks = new ArrayList<RemoteTask>();
1711             mTasksToBeNotifiedByClientId.put(clientId, remoteTasks);
1712         }
1713         remoteTasks.add(task);
1714         mHandler.postPendingTaskTimeout(task, task.timeoutInMs);
1715     }
1716 
onPendingTaskTimeout(RemoteTask task)1717     private void onPendingTaskTimeout(RemoteTask task) {
1718         long now = SystemClock.uptimeMillis();
1719         Slogf.w(TAG, "Pending task: %s timeout at %d", task, now);
1720         synchronized (mLock) {
1721             List<RemoteTask> pendingTasks = mTasksToBeNotifiedByClientId.get(task.clientId);
1722             if (pendingTasks == null) {
1723                 // The task is already delivered. Do nothing.
1724                 return;
1725             }
1726             pendingTasks.remove(task);
1727         }
1728     }
1729 
1730     @GuardedBy("mLock")
1731     @Nullable
popTasksFromPendingQueueLocked(String clientId)1732     private List<RemoteTask> popTasksFromPendingQueueLocked(String clientId) {
1733         if (DEBUG) {
1734             Slogf.d(TAG, "Pop pending remote tasks from queue for client ID: %s", clientId);
1735         }
1736         List<RemoteTask> pendingTasks = mTasksToBeNotifiedByClientId.get(clientId);
1737         if (pendingTasks == null) {
1738             return null;
1739         }
1740         mTasksToBeNotifiedByClientId.remove(clientId);
1741         for (int i = 0; i < pendingTasks.size(); i++) {
1742             if (DEBUG) {
1743                 Slogf.d(TAG, "Prepare to deliver remote task: %s", pendingTasks.get(i));
1744             }
1745             mHandler.cancelPendingTaskTimeout(pendingTasks.get(i));
1746         }
1747         return pendingTasks;
1748     }
1749 
generateNewTaskId()1750     private String generateNewTaskId() {
1751         return TASK_PREFIX + "_" + mTaskCount.incrementAndGet() + "_"
1752                 + CarServiceUtils.generateRandomAlphaNumericString(RANDOM_STRING_LENGTH);
1753     }
1754 
generateNewClientId()1755     private String generateNewClientId() {
1756         return CLIENT_PREFIX + "_" + mClientCount.incrementAndGet() + "_"
1757                 + CarServiceUtils.generateRandomAlphaNumericString(RANDOM_STRING_LENGTH);
1758     }
1759 
1760     @ExcludeFromCodeCoverageGeneratedReport(reason = DUMP_INFO)
nextPowerStateToString(int nextPowerState)1761     private static String nextPowerStateToString(int nextPowerState) {
1762         switch (nextPowerState) {
1763             case CarRemoteAccessManager.NEXT_POWER_STATE_ON:
1764                 return "ON";
1765             case CarRemoteAccessManager.NEXT_POWER_STATE_OFF:
1766                 return "OFF";
1767             case CarRemoteAccessManager.NEXT_POWER_STATE_SUSPEND_TO_RAM:
1768                 return "Suspend-to-RAM";
1769             case CarRemoteAccessManager.NEXT_POWER_STATE_SUSPEND_TO_DISK:
1770                 return "Suspend-to-disk";
1771             default:
1772                 return "Unknown(" + nextPowerState + ")";
1773         }
1774     }
1775 
1776     private static final class RemoteTaskClientServiceInfo {
1777         private final ComponentName mServiceComponentName;
1778         private final AtomicReference<RemoteTaskClientServiceConnection> mConnection =
1779                 new AtomicReference<>(null);
1780 
RemoteTaskClientServiceInfo(ComponentName componentName)1781         private RemoteTaskClientServiceInfo(ComponentName componentName) {
1782             mServiceComponentName = componentName;
1783         }
1784 
getServiceComponentName()1785         public ComponentName getServiceComponentName() {
1786             return mServiceComponentName;
1787         }
1788 
getServiceConnection()1789         public RemoteTaskClientServiceConnection getServiceConnection() {
1790             return mConnection.get();
1791         }
1792 
setServiceConnection(@ullable RemoteTaskClientServiceConnection connection)1793         public void setServiceConnection(@Nullable RemoteTaskClientServiceConnection connection) {
1794             mConnection.set(connection);
1795         }
1796 
1797         @Override
toString()1798         public String toString() {
1799             return new StringBuilder()
1800                     .append("RemoteTaskClientServiceInfo[")
1801                     .append("Component name=")
1802                     .append(mServiceComponentName)
1803                     .append(", hasConnection=")
1804                     .append(mConnection.get() != null)
1805                     .append("]")
1806                     .toString();
1807         }
1808     }
1809 
1810     private static final class RemoteTask {
1811         public final String id;
1812         public final byte[] data;
1813         public final String clientId;
1814         public final long timeoutInMs;
1815 
RemoteTask(String id, byte[] data, String clientId, long timeoutInMs)1816         private RemoteTask(String id, byte[] data, String clientId, long timeoutInMs) {
1817             this.id = id;
1818             this.data = data;
1819             this.clientId = clientId;
1820             this.timeoutInMs = timeoutInMs;
1821         }
1822 
1823         @Override
toString()1824         public String toString() {
1825             return new StringBuilder()
1826                     .append("RemoteTask[")
1827                     .append("taskId=")
1828                     .append(id)
1829                     .append("clientId=")
1830                     .append(clientId)
1831                     .append("timeoutInMs=")
1832                     .append(timeoutInMs)
1833                     .append("]")
1834                     .toString();
1835         }
1836     }
1837 
1838     private static final class ClientToken implements IBinder.DeathRecipient {
1839 
1840         private final Object mTokenLock = new Object();
1841         private final String mClientId;
1842         private final long mIdCreationTimeInMs;
1843         private final boolean mIsServerless;
1844 
1845         @GuardedBy("mTokenLock")
1846         private ICarRemoteAccessCallback mCallback;
1847         @GuardedBy("mTokenLock")
1848         private boolean mIsReadyForShutdown;
1849 
ClientToken(String clientId, long idCreationTimeInMs)1850         private ClientToken(String clientId, long idCreationTimeInMs) {
1851             this(clientId, idCreationTimeInMs, /* isServerless= */ false);
1852         }
1853 
ClientToken(String clientId, long idCreationTimeInMs, boolean isServerless)1854         private ClientToken(String clientId, long idCreationTimeInMs, boolean isServerless) {
1855             mClientId = clientId;
1856             mIdCreationTimeInMs = idCreationTimeInMs;
1857             mIsServerless = isServerless;
1858         }
1859 
isServerless()1860         public boolean isServerless() {
1861             return mIsServerless;
1862         }
1863 
getClientId()1864         public String getClientId() {
1865             return mClientId;
1866         }
1867 
getIdCreationTime()1868         public long getIdCreationTime() {
1869             return mIdCreationTimeInMs;
1870         }
1871 
getCallback()1872         public ICarRemoteAccessCallback getCallback() {
1873             synchronized (mTokenLock) {
1874                 return mCallback;
1875             }
1876         }
1877 
setCallback(ICarRemoteAccessCallback callback)1878         public void setCallback(ICarRemoteAccessCallback callback) {
1879             synchronized (mTokenLock) {
1880                 mCallback = callback;
1881             }
1882         }
1883 
setIsReadyForShutdown()1884         public void setIsReadyForShutdown() {
1885             synchronized (mTokenLock) {
1886                 mIsReadyForShutdown = true;
1887             }
1888         }
1889 
isReadyForShutdown()1890         public boolean isReadyForShutdown() {
1891             synchronized (mTokenLock) {
1892                 return mIsReadyForShutdown;
1893             }
1894         }
1895 
1896         @Override
binderDied()1897         public void binderDied() {
1898             synchronized (mTokenLock) {
1899                 Slogf.w(TAG, "Client token callback binder died");
1900                 mCallback.asBinder().unlinkToDeath(this, /* flags= */ 0);
1901                 mCallback = null;
1902             }
1903         }
1904 
1905         @Override
toString()1906         public String toString() {
1907             synchronized (mTokenLock) {
1908                 return new StringBuilder()
1909                         .append("ClientToken[")
1910                         .append("mClientId=").append(mClientId)
1911                         .append(", mIdCreationTimeInMs=").append(mIdCreationTimeInMs)
1912                         .append(", hasCallback=").append(mCallback != null)
1913                         .append(", isServerless=").append(mIsServerless)
1914                         .append(']')
1915                         .toString();
1916             }
1917         }
1918     }
1919 
1920     private static final class RemoteTaskClientServiceConnection implements ServiceConnection {
1921 
1922         private static final String TAG = RemoteTaskClientServiceConnection.class.getSimpleName();
1923 
1924         private final Object mServiceLock = new Object();
1925         private final Context mContext;
1926         private final Intent mIntent;
1927         private final UserHandle mUser;
1928         private final RemoteTaskClientServiceHandler mHandler;
1929         private final UserManager mUserManager;
1930         private final int mUid;
1931         private final long mTaskUnbindDelayMs;
1932 
1933         private final CarUserService mCarUserService;
1934 
1935         // The following three variables represent the state machine of this connection:
1936         // 1. Init state (Binding: F, Bound: F, WaitingForUserUnlock: F)
1937         // 2. Waiting for user unlock (Binding: F, Bound: F, WaitingForUserUnlock: T)
1938         // 3. Binding state (Binding: T, Bound: F, WaitingForUserUnlock: F)
1939         // 4. Bound state (Binding: F, Bound: T, WaitingForUserUnlock: F)
1940         //
1941         // 1->2 If user is currently locked
1942         // 2->3 Aftr receiving user unlock intent.
1943         // 1->3 If user is currently unlocked
1944         // 3->4 After onNullBinding callback.
1945         @GuardedBy("mServiceLock")
1946         private boolean mBound;
1947         @GuardedBy("mServiceLock")
1948         private boolean mBinding;
1949         @GuardedBy("mServiceLock")
1950         private boolean mWaitingForUserUnlock;
1951         @GuardedBy("mServiceLock")
1952         private long mTaskTimeoutMs;
1953         @GuardedBy("mServiceLock")
1954         private final Set<String> mActiveTasks = new ArraySet<>();
1955 
1956         private final UserLifecycleListener mUserLifecycleListener;
1957 
RemoteTaskClientServiceConnection(Context context, RemoteTaskClientServiceHandler handler, UserManager userManager, ComponentName serviceName, UserHandle user, int uid, long taskUnbindDelayMs)1958         private RemoteTaskClientServiceConnection(Context context,
1959                 RemoteTaskClientServiceHandler handler, UserManager userManager,
1960                 ComponentName serviceName, UserHandle user, int uid, long taskUnbindDelayMs) {
1961             mContext = context;
1962             mHandler = handler;
1963             mUserManager = userManager;
1964             mIntent = new Intent();
1965             mIntent.setComponent(serviceName);
1966             mUser = user;
1967             mUid = uid;
1968             mTaskUnbindDelayMs = taskUnbindDelayMs;
1969             mCarUserService = CarLocalServices.getService(CarUserService.class);
1970             mUserLifecycleListener = event -> {
1971                 if (!isEventOfType(TAG, event, USER_LIFECYCLE_EVENT_TYPE_UNLOCKED)) {
1972                     return;
1973                 }
1974 
1975                 if (event.getUserId() == mUser.getIdentifier()) {
1976                     onReceiveUserUnlock();
1977                 }
1978             };
1979         }
1980 
1981         @Override
onNullBinding(ComponentName name)1982         public void onNullBinding(ComponentName name) {
1983             synchronized (mServiceLock) {
1984                 mBound = true;
1985                 mBinding = false;
1986             }
1987             Slogf.i(TAG, "Service(%s) is bound", name.flattenToShortString());
1988         }
1989 
1990         @Override
onServiceConnected(ComponentName name, IBinder service)1991         public void onServiceConnected(ComponentName name, IBinder service) {
1992             // Do nothing.
1993         }
1994 
1995         @Override
onServiceDisconnected(ComponentName name)1996         public void onServiceDisconnected(ComponentName name) {
1997             // Do nothing.
1998         }
1999 
2000         @Override
onBindingDied(ComponentName name)2001         public void onBindingDied(ComponentName name) {
2002             Slogf.w(TAG, "Service(%s) died", name.flattenToShortString());
2003             unbindService(/* force= */ true);
2004         }
2005 
onReceiveUserUnlock()2006         private void onReceiveUserUnlock() {
2007             synchronized (mServiceLock) {
2008                 mWaitingForUserUnlock = false;
2009                 Slogf.i(TAG, "received user unlock notification");
2010                 if (mBinding || mBound) {
2011                     // bindService is called again after user is unlocked, which caused binding to
2012                     // happen, so we don't need to do anything here.
2013                     if (DEBUG) {
2014                         Slogf.d(TAG, "a binding is already created, ignore the user unlock intent");
2015                     }
2016                     return;
2017                 }
2018                 bindServiceLocked();
2019             }
2020         }
2021 
2022         @GuardedBy("mServiceLock")
waitForUserUnlockServiceLocked()2023         private void waitForUserUnlockServiceLocked() {
2024             UserLifecycleEventFilter userUnlockEventFilter = new UserLifecycleEventFilter.Builder()
2025                     .addEventType(USER_LIFECYCLE_EVENT_TYPE_UNLOCKED).addUser(mUser).build();
2026             mCarUserService.addUserLifecycleListener(userUnlockEventFilter, mUserLifecycleListener);
2027             mWaitingForUserUnlock = true;
2028         }
2029 
2030         @GuardedBy("mServiceLock")
cancelWaitForUserUnlockServiceLocked()2031         private void cancelWaitForUserUnlockServiceLocked() {
2032             mCarUserService.removeUserLifecycleListener(mUserLifecycleListener);
2033             mWaitingForUserUnlock = false;
2034         }
2035 
2036         @GuardedBy("mServiceLock")
bindServiceLocked()2037         private void bindServiceLocked() {
2038             Slogf.i(TAG, "Bind service %s as user %s", mIntent, mUser);
2039             boolean status = mContext.bindServiceAsUser(mIntent, /* conn= */ this,
2040                     BIND_AUTO_CREATE, mUser);
2041             if (!status) {
2042                 Slogf.w(TAG, "Failed to bind service %s as user %s", mIntent, mUser);
2043                 mContext.unbindService(/* conn= */ this);
2044                 return;
2045             }
2046             mBinding = true;
2047         }
2048 
2049         @GuardedBy("mServiceLock")
bindServiceIfUserUnlockedLocked()2050         private void bindServiceIfUserUnlockedLocked() {
2051             if (DEBUG) {
2052                 Slogf.d(TAG, "Try to bind service %s as user %s if unlocked", mIntent, mUser);
2053             }
2054             if (mBinding) {
2055                 Slogf.w(TAG, "%s binding is already ongoing, ignore the new bind request",
2056                         mIntent);
2057                 return;
2058             }
2059             if (mWaitingForUserUnlock) {
2060                 Slogf.w(TAG,
2061                         "%s binding is waiting for user unlock, ignore the new bind request",
2062                         mIntent);
2063                 return;
2064             }
2065             if (mBound) {
2066                 Slogf.w(TAG, "%s is already bound", mIntent);
2067                 return;
2068             }
2069             // Start listening for unlock event before checking so that we don't miss any
2070             // unlock intent.
2071             waitForUserUnlockServiceLocked();
2072             if (mUserManager.isUserUnlocked(mUser)) {
2073                 if (DEBUG) {
2074                     Slogf.d(TAG, "User %s is unlocked, start binding", mUser);
2075                 }
2076                 cancelWaitForUserUnlockServiceLocked();
2077             } else {
2078                 Slogf.w(TAG, "User %s is not unlocked, waiting for it to be unlocked", mUser);
2079                 return;
2080             }
2081             bindServiceLocked();
2082         }
2083 
unbindService(boolean force)2084         public boolean unbindService(boolean force) {
2085             synchronized (mServiceLock) {
2086                 return unbindServiceLocked(force);
2087             }
2088         }
2089 
2090         @GuardedBy("mServiceLock")
unbindServiceLocked(boolean force)2091         private boolean unbindServiceLocked(boolean force) {
2092             long currentTimeMs = SystemClock.uptimeMillis();
2093             if (!force && currentTimeMs < mTaskTimeoutMs) {
2094                 Slogf.w(TAG, "Unbind request is out-dated and is ignored");
2095                 return false;
2096             }
2097             Slogf.i(TAG, "unbindServiceLocked");
2098             mActiveTasks.clear();
2099             mHandler.cancelServiceTimeout(mUid);
2100             if (mWaitingForUserUnlock) {
2101                 cancelWaitForUserUnlockServiceLocked();
2102                 Slogf.w(TAG, "Still waiting for user unlock and bind has not started, "
2103                         + "ignore unbind");
2104                 return false;
2105             }
2106             if (!mBound && !mBinding) {
2107                 // If we do not have an active bounding.
2108                 Slogf.w(TAG, "No active binding, ignore unbind");
2109                 return false;
2110             }
2111             mBinding = false;
2112             mBound = false;
2113             try {
2114                 mContext.unbindService(/* conn= */ this);
2115             } catch (Exception e) {
2116                 Slogf.e(TAG, e, "failed to unbind service");
2117             }
2118             return true;
2119         }
2120 
2121         // Bind the service if user is unlocked or waiting for user unlock. Extend the task timeout
2122         // to be taskTimeoutMs.
bindServiceAndExtendTaskTimeoutMs(long taskTimeoutMs)2123         public void bindServiceAndExtendTaskTimeoutMs(long taskTimeoutMs) {
2124             Slogf.i(TAG, "Try to bind service %s as user %s if unlocked, timeout: %d", mIntent,
2125                     mUser, taskTimeoutMs);
2126             synchronized (mServiceLock) {
2127                 // Always bind the service to extend its lifetime. If the service is already bound,
2128                 // it will do nothing.
2129                 bindServiceIfUserUnlockedLocked();
2130                 if (mTaskTimeoutMs >= taskTimeoutMs) {
2131                     if (DEBUG) {
2132                         Slogf.d(TAG, "The service: %s new task timeout: %d ms is <= existing"
2133                                 + " task timeout: %d ms, ignore", mIntent, taskTimeoutMs,
2134                                 mTaskTimeoutMs);
2135                     }
2136                     return;
2137                 }
2138                 mTaskTimeoutMs = taskTimeoutMs;
2139                 mHandler.postServiceTimeout(mUid, taskTimeoutMs);
2140             }
2141         }
2142 
getActiveTaskCount()2143         public int getActiveTaskCount() {
2144             synchronized (mServiceLock) {
2145                 return mActiveTasks.size();
2146             }
2147         }
2148 
addActiveTasks(ArraySet<String> tasks)2149         public void addActiveTasks(ArraySet<String> tasks) {
2150             if (DEBUG) {
2151                 Slogf.d(TAG, "Add active tasks: %s for service %s", tasks, mIntent);
2152             }
2153             synchronized (mServiceLock) {
2154                 for (int i = 0; i < tasks.size(); i++) {
2155                     mActiveTasks.add(tasks.valueAt(i));
2156                 }
2157             }
2158         }
2159 
2160         // Remove the task IDs from the active tasks list for this connection. Return false if
2161         // one of the provided task is not in the list.
removeActiveTasks(ArraySet<String> tasks)2162         public boolean removeActiveTasks(ArraySet<String> tasks) {
2163             synchronized (mServiceLock) {
2164                 if (DEBUG) {
2165                     Slogf.d(TAG, "Remove active tasks: %s for service %s, current active tasks %s",
2166                             tasks, mIntent, mActiveTasks);
2167                 }
2168                 for (int i = 0; i < tasks.size(); i++) {
2169                     if (!mActiveTasks.contains(tasks.valueAt(i))) {
2170                         return false;
2171                     }
2172                     mActiveTasks.remove(tasks.valueAt(i));
2173                 }
2174                 if (mActiveTasks.isEmpty()) {
2175                     handleAllTasksCompletionLocked();
2176                 }
2177             }
2178             return true;
2179         }
2180 
removeAllActiveTasks()2181         public void removeAllActiveTasks() {
2182             synchronized (mServiceLock) {
2183                 mActiveTasks.clear();
2184                 handleAllTasksCompletionLocked();
2185             }
2186         }
2187 
2188         @GuardedBy("mServiceLock")
handleAllTasksCompletionLocked()2189         private void handleAllTasksCompletionLocked() {
2190             // All active tasks are completed for this package, we can now unbind the service after
2191             // mTaskUnbindDelayMs.
2192             Slogf.i(TAG, "All tasks completed for service: %s", mIntent);
2193             long currentTimeMs = SystemClock.uptimeMillis();
2194             if (DEBUG) {
2195                 Slogf.d(TAG, "Unbind remote task client service: %s after %d ms, "
2196                         + "current time: %d ms", mIntent, mTaskUnbindDelayMs,
2197                         currentTimeMs);
2198             }
2199             mTaskTimeoutMs = currentTimeMs + mTaskUnbindDelayMs;
2200             mHandler.postServiceTimeout(mUid, mTaskTimeoutMs);
2201         }
2202     }
2203 
2204     private static final class RemoteTaskClientServiceHandler extends Handler {
2205 
2206         private static final String TAG = RemoteTaskClientServiceHandler.class.getSimpleName();
2207         private static final int MSG_SERVICE_TIMEOUT = 1;
2208         private static final int MSG_WRAP_UP_REMOTE_ACCESS_SERVICE = 2;
2209         private static final int MSG_NOTIFY_SHUTDOWN_STARTING = 3;
2210         private static final int MSG_NOTIFY_AP_STATE_CHANGE = 4;
2211         private static final int MSG_MAYBE_SHUTDOWN = 5;
2212         private static final int MSG_PENDING_TASK_TIMEOUT = 6;
2213 
2214         // Lock to synchronize remove messages and add messages.
2215         private final Object mHandlerLock = new Object();
2216         private final WeakReference<CarRemoteAccessService> mService;
2217 
RemoteTaskClientServiceHandler(Looper looper, CarRemoteAccessService service)2218         private RemoteTaskClientServiceHandler(Looper looper, CarRemoteAccessService service) {
2219             super(looper);
2220             mService = new WeakReference<>(service);
2221         }
2222 
2223         // Must use uid instead of uidName here because message object is compared using "=="
2224         // instead fo equals, so two same string might not "==" each other.
postServiceTimeout(Integer uid, long msgTimeMs)2225         private void postServiceTimeout(Integer uid, long msgTimeMs) {
2226             synchronized (mHandlerLock) {
2227                 HandlerHelper.removeEqualMessages(this, MSG_SERVICE_TIMEOUT, uid);
2228                 Message msg = obtainMessage(MSG_SERVICE_TIMEOUT, uid);
2229                 sendMessageAtTime(msg, msgTimeMs);
2230             }
2231         }
2232 
postNotifyShutdownStarting(long delayMs)2233         private void postNotifyShutdownStarting(long delayMs) {
2234             synchronized (mHandlerLock) {
2235                 removeMessages(MSG_NOTIFY_SHUTDOWN_STARTING);
2236                 Message msg = obtainMessage(MSG_NOTIFY_SHUTDOWN_STARTING);
2237                 sendMessageDelayed(msg, delayMs);
2238             }
2239         }
2240 
postWrapUpRemoteAccessService(long delayMs)2241         private void postWrapUpRemoteAccessService(long delayMs) {
2242             synchronized (mHandlerLock) {
2243                 removeMessages(MSG_WRAP_UP_REMOTE_ACCESS_SERVICE);
2244                 Message msg = obtainMessage(MSG_WRAP_UP_REMOTE_ACCESS_SERVICE);
2245                 sendMessageDelayed(msg, delayMs);
2246             }
2247         }
2248 
postNotifyApStateChange(long delayMs)2249         private void postNotifyApStateChange(long delayMs) {
2250             synchronized (mHandlerLock) {
2251                 removeMessages(MSG_NOTIFY_AP_STATE_CHANGE);
2252                 Message msg = obtainMessage(MSG_NOTIFY_AP_STATE_CHANGE);
2253                 sendMessageDelayed(msg, delayMs);
2254             }
2255         }
2256 
postMaybeShutdown(long delayMs)2257         private void postMaybeShutdown(long delayMs) {
2258             synchronized (mHandlerLock) {
2259                 removeMessages(MSG_MAYBE_SHUTDOWN);
2260                 Message msg = obtainMessage(MSG_MAYBE_SHUTDOWN);
2261                 sendMessageDelayed(msg, delayMs);
2262             }
2263         }
2264 
postPendingTaskTimeout(RemoteTask task, long msgTimeMs)2265         private void postPendingTaskTimeout(RemoteTask task, long msgTimeMs) {
2266             Message msg = obtainMessage(MSG_PENDING_TASK_TIMEOUT, task);
2267             sendMessageAtTime(msg, msgTimeMs);
2268         }
2269 
cancelServiceTimeout(int uid)2270         private void cancelServiceTimeout(int uid) {
2271             HandlerHelper.removeEqualMessages(this, MSG_SERVICE_TIMEOUT, uid);
2272         }
2273 
cancelAllServiceTimeout()2274         private void cancelAllServiceTimeout() {
2275             removeMessages(MSG_SERVICE_TIMEOUT);
2276         }
2277 
cancelNotifyShutdownStarting()2278         private void cancelNotifyShutdownStarting() {
2279             removeMessages(MSG_NOTIFY_SHUTDOWN_STARTING);
2280         }
2281 
cancelWrapUpRemoteAccessService()2282         private void cancelWrapUpRemoteAccessService() {
2283             removeMessages(MSG_WRAP_UP_REMOTE_ACCESS_SERVICE);
2284         }
2285 
cancelNotifyApStateChange()2286         private void cancelNotifyApStateChange() {
2287             removeMessages(MSG_NOTIFY_AP_STATE_CHANGE);
2288         }
2289 
cancelMaybeShutdown()2290         private void cancelMaybeShutdown() {
2291             removeMessages(MSG_MAYBE_SHUTDOWN);
2292         }
2293 
cancelPendingTaskTimeout(RemoteTask task)2294         private void cancelPendingTaskTimeout(RemoteTask task) {
2295             removeMessages(MSG_PENDING_TASK_TIMEOUT, task);
2296         }
2297 
cancelAllPendingTaskTimeout()2298         private void cancelAllPendingTaskTimeout() {
2299             removeMessages(MSG_PENDING_TASK_TIMEOUT);
2300         }
2301 
cancelAll()2302         private void cancelAll() {
2303             cancelAllServiceTimeout();
2304             cancelNotifyShutdownStarting();
2305             cancelWrapUpRemoteAccessService();
2306             cancelNotifyApStateChange();
2307             cancelMaybeShutdown();
2308             cancelAllPendingTaskTimeout();
2309         }
2310 
2311         @Override
handleMessage(Message msg)2312         public void handleMessage(Message msg) {
2313             CarRemoteAccessService service = mService.get();
2314             if (service == null) {
2315                 Slogf.w(TAG, "CarRemoteAccessService is not available");
2316                 return;
2317             }
2318             switch (msg.what) {
2319                 case MSG_SERVICE_TIMEOUT:
2320                     service.onServiceTimeout((Integer) msg.obj);
2321                     break;
2322                 case MSG_WRAP_UP_REMOTE_ACCESS_SERVICE:
2323                     service.wrapUpRemoteAccessServiceIfNeeded();
2324                     break;
2325                 case MSG_NOTIFY_SHUTDOWN_STARTING:
2326                     service.notifyShutdownStarting();
2327                     break;
2328                 case MSG_NOTIFY_AP_STATE_CHANGE:
2329                     service.notifyApStateChange();
2330                     break;
2331                 case MSG_MAYBE_SHUTDOWN:
2332                     service.shutdownIfNeeded(/* force= */ false);
2333                     break;
2334                 case MSG_PENDING_TASK_TIMEOUT:
2335                     service.onPendingTaskTimeout((RemoteTask) msg.obj);
2336                     break;
2337                 default:
2338                     Slogf.w(TAG, "Unknown(%d) message", msg.what);
2339             }
2340         }
2341     }
2342 }
2343