• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 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.server.autofill;
18 
19 import static android.service.autofill.FillEventHistory.Event.NO_SAVE_UI_REASON_NONE;
20 import static android.service.autofill.FillEventHistory.Event.UI_TYPE_INLINE;
21 import static android.service.autofill.FillRequest.FLAG_MANUAL_REQUEST;
22 import static android.service.autofill.FillRequest.FLAG_VIEW_REQUESTS_CREDMAN_SERVICE;
23 import static android.view.autofill.AutofillManager.ACTION_START_SESSION;
24 import static android.view.autofill.AutofillManager.FLAG_ADD_CLIENT_ENABLED;
25 import static android.view.autofill.AutofillManager.FLAG_ADD_CLIENT_ENABLED_FOR_AUGMENTED_AUTOFILL_ONLY;
26 import static android.view.autofill.AutofillManager.NO_SESSION;
27 import static android.view.autofill.AutofillManager.RECEIVER_FLAG_SESSION_FOR_AUGMENTED_AUTOFILL_ONLY;
28 
29 import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
30 import static com.android.server.autofill.Helper.sDebug;
31 import static com.android.server.autofill.Helper.sVerbose;
32 
33 import android.annotation.NonNull;
34 import android.annotation.Nullable;
35 import android.app.ActivityManagerInternal;
36 import android.content.ComponentName;
37 import android.content.Context;
38 import android.content.Intent;
39 import android.content.pm.PackageManager;
40 import android.content.pm.PackageManager.NameNotFoundException;
41 import android.content.pm.ResolveInfo;
42 import android.content.pm.ServiceInfo;
43 import android.graphics.Rect;
44 import android.metrics.LogMaker;
45 import android.os.AsyncTask;
46 import android.os.Binder;
47 import android.os.Bundle;
48 import android.os.Handler;
49 import android.os.IBinder;
50 import android.os.Looper;
51 import android.os.Process;
52 import android.os.RemoteCallbackList;
53 import android.os.RemoteException;
54 import android.os.SystemClock;
55 import android.os.UserHandle;
56 import android.provider.Settings;
57 import android.service.autofill.AutofillService;
58 import android.service.autofill.AutofillServiceInfo;
59 import android.service.autofill.FieldClassification;
60 import android.service.autofill.FieldClassification.Match;
61 import android.service.autofill.FillEventHistory;
62 import android.service.autofill.FillEventHistory.Event;
63 import android.service.autofill.FillEventHistory.Event.NoSaveReason;
64 import android.service.autofill.FillResponse;
65 import android.service.autofill.Flags;
66 import android.service.autofill.IAutoFillService;
67 import android.service.autofill.InlineSuggestionRenderService;
68 import android.service.autofill.SaveInfo;
69 import android.service.autofill.UserData;
70 import android.util.ArrayMap;
71 import android.util.ArraySet;
72 import android.util.DebugUtils;
73 import android.util.LocalLog;
74 import android.util.Pair;
75 import android.util.Slog;
76 import android.util.SparseArray;
77 import android.view.autofill.AutofillFeatureFlags;
78 import android.view.autofill.AutofillId;
79 import android.view.autofill.AutofillManager;
80 import android.view.autofill.AutofillManager.AutofillCommitReason;
81 import android.view.autofill.AutofillManager.SmartSuggestionMode;
82 import android.view.autofill.AutofillValue;
83 import android.view.autofill.IAutoFillManagerClient;
84 
85 import com.android.internal.R;
86 import com.android.internal.annotations.GuardedBy;
87 import com.android.internal.logging.MetricsLogger;
88 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
89 import com.android.internal.os.IResultReceiver;
90 import com.android.server.LocalServices;
91 import com.android.server.autofill.AutofillManagerService.AutofillCompatState;
92 import com.android.server.autofill.AutofillManagerService.DisabledInfoCache;
93 import com.android.server.autofill.RemoteAugmentedAutofillService.RemoteAugmentedAutofillServiceCallbacks;
94 import com.android.server.autofill.ui.AutoFillUI;
95 import com.android.server.contentcapture.ContentCaptureManagerInternal;
96 import com.android.server.infra.AbstractPerUserSystemService;
97 import com.android.server.inputmethod.InputMethodManagerInternal;
98 import com.android.server.pm.UserManagerInternal;
99 import com.android.server.wm.ActivityTaskManagerInternal;
100 
101 import java.io.PrintWriter;
102 import java.util.ArrayList;
103 import java.util.List;
104 import java.util.Objects;
105 import java.util.Random;
106 
107 /**
108  * Bridge between the {@code system_server}'s {@link AutofillManagerService} and the
109  * app's {@link IAutoFillService} implementation.
110  *
111  */
112 final class AutofillManagerServiceImpl
113         extends AbstractPerUserSystemService<AutofillManagerServiceImpl, AutofillManagerService> {
114 
115     private static final String TAG = "AutofillManagerServiceImpl";
116     private static final int MAX_SESSION_ID_CREATE_TRIES = 2048;
117 
118     /** Minimum interval to prune abandoned sessions */
119     private static final int MAX_ABANDONED_SESSION_MILLIS = 30_000;
120 
121     private final AutoFillUI mUi;
122     private final MetricsLogger mMetricsLogger = new MetricsLogger();
123 
124     @GuardedBy("mLock")
125     private RemoteCallbackList<IAutoFillManagerClient> mClients;
126 
127     @GuardedBy("mLock")
128     private AutofillServiceInfo mInfo;
129 
130     private static final Random sRandom = new Random();
131 
132     private final LocalLog mUiLatencyHistory;
133     private final LocalLog mWtfHistory;
134     private final FieldClassificationStrategy mFieldClassificationStrategy;
135 
136     @GuardedBy("mLock")
137     @Nullable
138     private RemoteInlineSuggestionRenderService mRemoteInlineSuggestionRenderService;
139 
140     /**
141      * Data used for field classification.
142      */
143     @GuardedBy("mLock")
144     private UserData mUserData;
145 
146     private final Handler mHandler = new Handler(Looper.getMainLooper(), null, true);
147 
148     /**
149      * Cache of pending {@link Session}s, keyed by sessionId.
150      *
151      * <p>They're kept until the {@link AutofillService} finished handling a request, an error
152      * occurs, or the session is abandoned.
153      */
154     @GuardedBy("mLock")
155     private final SparseArray<Session> mSessions = new SparseArray<>();
156 
157     /**
158      * Cache of FillEventHistory for active Sessions.
159      *
160      * <p>New histories are added whenever a Session is created and are kept until Sessions are
161      * removed through removeSessionLocked()
162      */
163     @GuardedBy("mLock")
164     private final SparseArray<FillEventHistory> mFillHistories = new SparseArray<>();
165 
166     /** The last selection */
167     @GuardedBy("mLock")
168     private FillEventHistory mEventHistory;
169 
170     /**
171      * The last inline augmented autofill selection. Note that we don't log the selection from the
172      * dropdown UI since the service owns the UI in that case.
173      */
174     @GuardedBy("mLock")
175     private FillEventHistory mAugmentedAutofillEventHistory;
176 
177     /** Shared instance, doesn't need to be logged */
178     private final AutofillCompatState mAutofillCompatState;
179 
180     /** When was {@link PruneTask} last executed? */
181     private long mLastPrune = 0;
182 
183     /**
184      * Reference to the {@link RemoteFieldClassificationService}, is set on demand.
185      */
186     @GuardedBy("mLock")
187     @Nullable
188     private RemoteFieldClassificationService mRemoteFieldClassificationService;
189 
190     @GuardedBy("mLock")
191     @Nullable
192     private ServiceInfo mRemoteFieldClassificationServiceInfo;
193 
194     /**
195      * Reference to the {@link RemoteAugmentedAutofillService}, is set on demand.
196      */
197     @GuardedBy("mLock")
198     @Nullable
199     private RemoteAugmentedAutofillService mRemoteAugmentedAutofillService;
200 
201     @GuardedBy("mLock")
202     @Nullable
203     private ServiceInfo mRemoteAugmentedAutofillServiceInfo;
204 
205     private final InputMethodManagerInternal mInputMethodManagerInternal;
206 
207     private final ContentCaptureManagerInternal mContentCaptureManagerInternal;
208 
209     private final UserManagerInternal mUserManagerInternal;
210 
211     private final DisabledInfoCache mDisabledInfoCache;
212 
AutofillManagerServiceImpl(AutofillManagerService master, Object lock, LocalLog uiLatencyHistory, LocalLog wtfHistory, int userId, AutoFillUI ui, AutofillCompatState autofillCompatState, boolean disabled, DisabledInfoCache disableCache)213     AutofillManagerServiceImpl(AutofillManagerService master, Object lock,
214             LocalLog uiLatencyHistory, LocalLog wtfHistory, int userId, AutoFillUI ui,
215             AutofillCompatState autofillCompatState,
216             boolean disabled, DisabledInfoCache disableCache) {
217         super(master, lock, userId);
218 
219         mUiLatencyHistory = uiLatencyHistory;
220         mWtfHistory = wtfHistory;
221         mUi = ui;
222         mFieldClassificationStrategy = new FieldClassificationStrategy(getContext(), userId);
223         mAutofillCompatState = autofillCompatState;
224         mInputMethodManagerInternal = LocalServices.getService(InputMethodManagerInternal.class);
225         mContentCaptureManagerInternal = LocalServices.getService(
226                 ContentCaptureManagerInternal.class);
227         mUserManagerInternal = LocalServices.getService(UserManagerInternal.class);
228         mDisabledInfoCache = disableCache;
229         updateLocked(disabled);
230     }
231 
sendActivityAssistDataToContentCapture(@onNull IBinder activityToken, @NonNull Bundle data)232     boolean sendActivityAssistDataToContentCapture(@NonNull IBinder activityToken,
233             @NonNull Bundle data) {
234         if (mContentCaptureManagerInternal != null) {
235             mContentCaptureManagerInternal.sendActivityAssistData(getUserId(), activityToken, data);
236             return true;
237         }
238 
239         return false;
240     }
241 
242     @GuardedBy("mLock")
onBackKeyPressed()243     void onBackKeyPressed() {
244         final RemoteAugmentedAutofillService remoteService =
245                 getRemoteAugmentedAutofillServiceLocked();
246         if (remoteService != null) {
247             remoteService.onDestroyAutofillWindowsRequest();
248         }
249     }
250 
251     @GuardedBy("mLock")
252     @Override // from PerUserSystemService
updateLocked(boolean disabled)253     protected boolean updateLocked(boolean disabled) {
254         forceRemoveAllSessionsLocked();
255         final boolean enabledChanged = super.updateLocked(disabled);
256         if (enabledChanged) {
257             if (!isEnabledLocked()) {
258                 final int sessionCount = mSessions.size();
259                 for (int i = sessionCount - 1; i >= 0; i--) {
260                     final Session session = mSessions.valueAt(i);
261                     session.removeFromServiceLocked();
262                 }
263             }
264             sendStateToClients(/* resetClient= */ false);
265         }
266         updateRemoteAugmentedAutofillService();
267         getRemoteInlineSuggestionRenderServiceLocked();
268 
269         return enabledChanged;
270     }
271 
272     @Override // from PerUserSystemService
newServiceInfoLocked(@onNull ComponentName serviceComponent)273     protected ServiceInfo newServiceInfoLocked(@NonNull ComponentName serviceComponent)
274             throws NameNotFoundException {
275         final List<ResolveInfo> resolveInfos =
276                 getContext().getPackageManager().queryIntentServicesAsUser(
277                     new Intent(AutofillService.SERVICE_INTERFACE),
278                     // The MATCH_INSTANT flag is added because curret autofill CTS module is
279                     // defined in one apk, which makes the test autofill service installed in a
280                     // instant app when the CTS tests are running in instant app mode.
281                     // TODO: Remove MATCH_INSTANT flag after completing refactoring the CTS module
282                     //       to make the test autofill service a separate apk.
283                     PackageManager.GET_META_DATA | PackageManager.MATCH_INSTANT,
284                     mUserId);
285         boolean serviceHasAutofillIntentFilter = false;
286         for (ResolveInfo resolveInfo : resolveInfos) {
287             final ServiceInfo serviceInfo = resolveInfo.serviceInfo;
288             if (serviceInfo.getComponentName().equals(serviceComponent)) {
289                 serviceHasAutofillIntentFilter = true;
290                 break;
291             }
292         }
293         if (!serviceHasAutofillIntentFilter) {
294             Slog.w(TAG,
295                     "Autofill service from '" + serviceComponent.getPackageName() + "' does"
296                             + "not have intent filter " + AutofillService.SERVICE_INTERFACE);
297             throw new SecurityException("Service does not declare intent filter "
298                             + AutofillService.SERVICE_INTERFACE);
299         }
300         mInfo = new AutofillServiceInfo(getContext(), serviceComponent, mUserId);
301         return mInfo.getServiceInfo();
302     }
303 
304     @Nullable
getUrlBarResourceIdsForCompatMode(@onNull String packageName)305     String[] getUrlBarResourceIdsForCompatMode(@NonNull String packageName) {
306         return mAutofillCompatState.getUrlBarResourceIds(packageName, mUserId);
307     }
308 
309     /**
310      * Adds the client and return the proper flags
311      *
312      * @return {@code 0} if disabled, {@code FLAG_ADD_CLIENT_ENABLED} if enabled (it might be
313      * OR'ed with {@code FLAG_AUGMENTED_AUTOFILL_REQUEST}).
314      */
addClientLocked(IAutoFillManagerClient client, ComponentName componentName, boolean credmanRequested)315     int addClientLocked(IAutoFillManagerClient client, ComponentName componentName,
316             boolean credmanRequested) {
317         synchronized (mLock) {
318             ComponentName credComponentName = getCredentialAutofillService(getContext());
319 
320             if (!credmanRequested
321                     && Objects.equals(credComponentName,
322                     mInfo == null ? null : mInfo.getServiceInfo().getComponentName())) {
323                 // If the service component name corresponds to cred component name, then it means
324                 // no autofill provider is selected by the user. Cred Autofill Service should only
325                 // be active if there is a credman request.
326                 return 0;
327             }
328             if (mClients == null) {
329                 mClients = new RemoteCallbackList<>();
330             }
331             mClients.register(client);
332 
333             if (isEnabledLocked()) return FLAG_ADD_CLIENT_ENABLED;
334 
335             // Check if it's enabled for augmented autofill
336             if (componentName != null && isAugmentedAutofillServiceAvailableLocked()
337                     && isWhitelistedForAugmentedAutofillLocked(componentName)) {
338                 return FLAG_ADD_CLIENT_ENABLED_FOR_AUGMENTED_AUTOFILL_ONLY;
339             }
340         }
341 
342         // No flags / disabled
343         return 0;
344     }
345 
346     @GuardedBy("mLock")
removeClientLocked(IAutoFillManagerClient client)347     void removeClientLocked(IAutoFillManagerClient client) {
348         if (mClients != null) {
349             mClients.unregister(client);
350         }
351     }
352 
353     @GuardedBy("mLock")
setAuthenticationResultLocked(Bundle data, int sessionId, int authenticationId, int uid)354     void setAuthenticationResultLocked(Bundle data, int sessionId, int authenticationId, int uid) {
355         if (!isEnabledLocked()) {
356             return;
357         }
358         final Session session = mSessions.get(sessionId);
359         if (session != null && uid == session.uid) {
360             synchronized (session.mLock) {
361                 session.setAuthenticationResultLocked(data, authenticationId);
362             }
363         }
364     }
365 
setHasCallback(int sessionId, int uid, boolean hasIt)366     void setHasCallback(int sessionId, int uid, boolean hasIt) {
367         if (!isEnabledLocked()) {
368             return;
369         }
370         final Session session = mSessions.get(sessionId);
371         if (session != null && uid == session.uid) {
372             synchronized (mLock) {
373                 session.setHasCallbackLocked(hasIt);
374             }
375         }
376     }
377 
378     /**
379      * Starts a new session.
380      *
381      * @return {@code long} whose right-most 32 bits represent the session id (which is always
382      * non-negative), and the left-most contains extra flags (currently either {@code 0} or
383      * {@link AutofillManager#RECEIVER_FLAG_SESSION_FOR_AUGMENTED_AUTOFILL_ONLY}).
384      */
385     @GuardedBy("mLock")
startSessionLocked(@onNull IBinder activityToken, int taskId, int clientUid, @NonNull IBinder clientCallback, @NonNull AutofillId autofillId, @NonNull Rect virtualBounds, @Nullable AutofillValue value, boolean hasCallback, @NonNull ComponentName clientActivity, boolean compatMode, boolean bindInstantServiceAllowed, int flags)386     long startSessionLocked(@NonNull IBinder activityToken, int taskId, int clientUid,
387             @NonNull IBinder clientCallback, @NonNull AutofillId autofillId,
388             @NonNull Rect virtualBounds, @Nullable AutofillValue value, boolean hasCallback,
389             @NonNull ComponentName clientActivity, boolean compatMode,
390             boolean bindInstantServiceAllowed, int flags) {
391         // FLAG_AUGMENTED_AUTOFILL_REQUEST is set in the flags when standard autofill is disabled
392         // but the package is allowlisted for augmented autofill
393         boolean forAugmentedAutofillOnly = (flags
394                 & FLAG_ADD_CLIENT_ENABLED_FOR_AUGMENTED_AUTOFILL_ONLY) != 0;
395         if (!isEnabledLocked() && !forAugmentedAutofillOnly) {
396             return 0;
397         }
398 
399         // TODO(b/376482880): remove this check once autofill service supports visible
400         // background users.
401         if (mUserManagerInternal.isVisibleBackgroundFullUser(mUserId)) {
402             Slog.d(TAG, "Currently, autofill service does not support visible background users.");
403             return 0;
404         }
405 
406         if (!forAugmentedAutofillOnly && isAutofillDisabledLocked(clientActivity)) {
407             // Standard autofill is enabled, but service disabled autofill for this activity; that
408             // means no session, unless the activity is allowlisted for augmented autofill
409             if (isWhitelistedForAugmentedAutofillLocked(clientActivity)) {
410                 if (sDebug) {
411                     Slog.d(TAG, "startSession(" + clientActivity + "): disabled by service but "
412                             + "whitelisted for augmented autofill");
413                 }
414                 forAugmentedAutofillOnly = true;
415 
416             } else {
417                 if (sDebug) {
418                     Slog.d(TAG, "startSession(" + clientActivity + "): ignored because "
419                             + "disabled by service and not whitelisted for augmented autofill");
420                 }
421                 final IAutoFillManagerClient client = IAutoFillManagerClient.Stub
422                         .asInterface(clientCallback);
423                 try {
424                     client.setSessionFinished(AutofillManager.STATE_DISABLED_BY_SERVICE,
425                             /* autofillableIds= */ null);
426                 } catch (RemoteException e) {
427                     Slog.w(TAG,
428                             "Could not notify " + clientActivity + " that it's disabled: " + e);
429                 }
430 
431                 return NO_SESSION;
432             }
433         }
434 
435         if (sVerbose) {
436             Slog.v(TAG, "startSession(): token=" + activityToken + ", flags=" + flags
437                     + ", forAugmentedAutofillOnly=" + forAugmentedAutofillOnly);
438         }
439 
440         // Occasionally clean up abandoned sessions
441         pruneAbandonedSessionsLocked();
442 
443         final Session newSession = createSessionByTokenLocked(activityToken, taskId, clientUid,
444                 clientCallback, hasCallback, clientActivity, compatMode,
445                 bindInstantServiceAllowed, forAugmentedAutofillOnly, flags);
446         if (newSession == null) {
447             return NO_SESSION;
448         }
449 
450         // Service can be null when it's only for augmented autofill
451         String servicePackageName = mInfo == null ? null : mInfo.getServiceInfo().packageName;
452         final String historyItem =
453                 "id=" + newSession.id + " uid=" + clientUid + " a=" + clientActivity.toShortString()
454                 + " s=" + servicePackageName
455                 + " u=" + mUserId + " i=" + autofillId + " b=" + virtualBounds
456                 + " hc=" + hasCallback + " f=" + flags + " aa=" + forAugmentedAutofillOnly;
457         mMaster.logRequestLocked(historyItem);
458 
459         synchronized (newSession.mLock) {
460             newSession.updateLocked(autofillId, virtualBounds, value, ACTION_START_SESSION, flags);
461         }
462 
463         if (forAugmentedAutofillOnly) {
464             // Must embed the flag in the response, at the high-end side of the long.
465             // (session is always positive, so we don't have to worry about the signal bit)
466             final long extraFlags =
467                     ((long) RECEIVER_FLAG_SESSION_FOR_AUGMENTED_AUTOFILL_ONLY) << 32;
468             final long result = extraFlags | newSession.id;
469             return result;
470         } else {
471             return newSession.id;
472         }
473     }
474 
475     /**
476      * Remove abandoned sessions if needed.
477      */
478     @GuardedBy("mLock")
pruneAbandonedSessionsLocked()479     private void pruneAbandonedSessionsLocked() {
480         long now = System.currentTimeMillis();
481         if (mLastPrune < now - MAX_ABANDONED_SESSION_MILLIS) {
482             mLastPrune = now;
483 
484             if (mSessions.size() > 0) {
485                 (new PruneTask()).execute();
486             }
487         }
488     }
489 
490     @GuardedBy("mLock")
setAutofillFailureLocked( int sessionId, int uid, @NonNull List<AutofillId> ids, boolean isRefill)491     void setAutofillFailureLocked(
492             int sessionId, int uid, @NonNull List<AutofillId> ids, boolean isRefill) {
493         if (!isEnabledLocked()) {
494             Slog.wtf(TAG, "Service not enabled");
495             return;
496         }
497         final Session session = mSessions.get(sessionId);
498         if (session == null || uid != session.uid) {
499             Slog.v(TAG, "setAutofillFailure(): no session for " + sessionId + "(" + uid + ")");
500             return;
501         }
502         session.setAutofillFailureLocked(ids, isRefill);
503     }
504 
505     @GuardedBy("mLock")
setViewAutofilledLocked(int sessionId, int uid, @NonNull AutofillId id)506     void setViewAutofilledLocked(int sessionId, int uid, @NonNull AutofillId id) {
507         if (!isEnabledLocked()) {
508             Slog.wtf(TAG, "Service not enabled");
509             return;
510         }
511         final Session session = mSessions.get(sessionId);
512         if (session == null || uid != session.uid) {
513             Slog.v(TAG, "setViewAutofilled(): no session for " + sessionId + "(" + uid + ")");
514             return;
515         }
516         session.setViewAutofilledLocked(id);
517     }
518 
519     @GuardedBy("mLock")
notifyNotExpiringResponseDuringAuth(int sessionId, int uid)520     void notifyNotExpiringResponseDuringAuth(int sessionId, int uid) {
521         if (!isEnabledLocked()) {
522             Slog.wtf(TAG, "Service not enabled");
523             return;
524         }
525         final Session session = mSessions.get(sessionId);
526         if (session == null || uid != session.uid) {
527             Slog.v(TAG, "notifyNotExpiringResponseDuringAuth(): no session for "
528                     + sessionId + "(" + uid + ")");
529             return;
530         }
531         session.setNotifyNotExpiringResponseDuringAuth();
532     }
533 
534     @GuardedBy("mLock")
notifyViewEnteredIgnoredDuringAuthCount(int sessionId, int uid)535     void notifyViewEnteredIgnoredDuringAuthCount(int sessionId, int uid) {
536         if (!isEnabledLocked()) {
537             Slog.wtf(TAG, "Service not enabled");
538             return;
539         }
540         final Session session = mSessions.get(sessionId);
541         if (session == null || uid != session.uid) {
542             Slog.v(TAG, "notifyViewEnteredIgnoredDuringAuthCount(): no session for "
543                     + sessionId + "(" + uid + ")");
544             return;
545         }
546         session.setLogViewEnteredIgnoredDuringAuth();
547     }
548 
549     @GuardedBy("mLock")
setAutofillIdsAttemptedForRefill( int sessionId, @NonNull List<AutofillId> ids, int uid)550     public void setAutofillIdsAttemptedForRefill(
551             int sessionId, @NonNull List<AutofillId> ids, int uid) {
552         if (!isEnabledLocked()) {
553             Slog.wtf(TAG, "Service not enabled");
554             return;
555         }
556         final Session session = mSessions.get(sessionId);
557         if (session == null || uid != session.uid) {
558             Slog.v(TAG, "setAutofillIdsAttemptedForRefill(): no session for "
559                     + sessionId + "(" + uid + ")");
560             return;
561         }
562         session.setAutofillIdsAttemptedForRefillLocked(ids);
563     }
564 
565     @GuardedBy("mLock")
finishSessionLocked(int sessionId, int uid, @AutofillCommitReason int commitReason)566     void finishSessionLocked(int sessionId, int uid, @AutofillCommitReason int commitReason) {
567         if (!isEnabledLocked()) {
568             Slog.wtf(TAG, "Service not enabled");
569             return;
570         }
571 
572         final Session session = mSessions.get(sessionId);
573         if (session == null || uid != session.uid) {
574             if (sVerbose) {
575                 Slog.v(TAG, "finishSessionLocked(): no session for " + sessionId + "(" + uid + ")");
576             }
577             return;
578         }
579 
580         final Session.SaveResult saveResult = session.showSaveLocked();
581 
582         session.logContextCommittedLocked(saveResult.getNoSaveUiReason(), commitReason);
583 
584         if (saveResult.isLogSaveShown()) {
585             session.logSaveUiShown();
586         }
587 
588         final boolean finished = saveResult.isRemoveSession();
589         if (sVerbose) {
590             Slog.v(TAG, "finishSessionLocked(): session finished? " + finished
591                     + ", showing save UI? " + saveResult.isLogSaveShown());
592         }
593 
594         if (finished) {
595             session.removeFromServiceLocked();
596         }
597     }
598 
599     @GuardedBy("mLock")
cancelSessionLocked(int sessionId, int uid)600     void cancelSessionLocked(int sessionId, int uid) {
601         if (!isEnabledLocked()) {
602             return;
603         }
604 
605         final Session session = mSessions.get(sessionId);
606         if (session == null || uid != session.uid) {
607             Slog.w(TAG, "cancelSessionLocked(): no session for " + sessionId + "(" + uid + ")");
608             return;
609         }
610         session.removeFromServiceLocked();
611     }
612 
613     @GuardedBy("mLock")
disableOwnedAutofillServicesLocked(int uid)614     void disableOwnedAutofillServicesLocked(int uid) {
615         Slog.i(TAG, "disableOwnedServices(" + uid + "): " + mInfo);
616         if (mInfo == null) return;
617 
618         final ServiceInfo serviceInfo = mInfo.getServiceInfo();
619         if (serviceInfo.applicationInfo.uid != uid) {
620             Slog.w(TAG, "disableOwnedServices(): ignored when called by UID " + uid
621                     + " instead of " + serviceInfo.applicationInfo.uid
622                     + " for service " + mInfo);
623             return;
624         }
625 
626 
627         final long identity = Binder.clearCallingIdentity();
628         try {
629             final String autoFillService = getComponentNameLocked();
630             final ComponentName componentName = serviceInfo.getComponentName();
631             if (componentName.equals(ComponentName.unflattenFromString(autoFillService))) {
632                 mMetricsLogger.action(MetricsEvent.AUTOFILL_SERVICE_DISABLED_SELF,
633                         componentName.getPackageName());
634                 Settings.Secure.putStringForUser(getContext().getContentResolver(),
635                         Settings.Secure.AUTOFILL_SERVICE, null, mUserId);
636                 forceRemoveAllSessionsLocked();
637             } else {
638                 Slog.w(TAG, "disableOwnedServices(): ignored because current service ("
639                         + serviceInfo + ") does not match Settings (" + autoFillService + ")");
640             }
641         } finally {
642             Binder.restoreCallingIdentity(identity);
643         }
644     }
645 
646     @GuardedBy("mLock")
createSessionByTokenLocked(@onNull IBinder clientActivityToken, int taskId, int clientUid, @NonNull IBinder clientCallback, boolean hasCallback, @NonNull ComponentName clientActivity, boolean compatMode, boolean bindInstantServiceAllowed, boolean forAugmentedAutofillOnly, int flags)647     private Session createSessionByTokenLocked(@NonNull IBinder clientActivityToken, int taskId,
648             int clientUid, @NonNull IBinder clientCallback, boolean hasCallback,
649             @NonNull ComponentName clientActivity, boolean compatMode,
650             boolean bindInstantServiceAllowed, boolean forAugmentedAutofillOnly, int flags) {
651         // use random ids so that one app cannot know that another app creates sessions
652         int sessionId;
653         int tries = 0;
654         do {
655             tries++;
656             if (tries > MAX_SESSION_ID_CREATE_TRIES) {
657                 Slog.w(TAG, "Cannot create session in " + MAX_SESSION_ID_CREATE_TRIES + " tries");
658                 return null;
659             }
660 
661             sessionId = Math.abs(sRandom.nextInt());
662         } while (sessionId == 0 || sessionId == NO_SESSION
663                 || mSessions.indexOfKey(sessionId) >= 0);
664 
665         assertCallerLocked(clientActivity, compatMode);
666         ComponentName serviceComponentName = mInfo == null ? null
667                 : mInfo.getServiceInfo().getComponentName();
668         boolean isPrimaryCredential = (flags & FLAG_VIEW_REQUESTS_CREDMAN_SERVICE) != 0;
669 
670         final Session newSession = new Session(this, mUi, getContext(), mHandler, mUserId, mLock,
671                 sessionId, taskId, clientUid, clientActivityToken, clientCallback, hasCallback,
672                 mUiLatencyHistory, mWtfHistory, serviceComponentName,
673                 clientActivity, compatMode, bindInstantServiceAllowed, forAugmentedAutofillOnly,
674                 flags, mInputMethodManagerInternal, isPrimaryCredential);
675         mSessions.put(newSession.id, newSession);
676 
677         if (AutofillFeatureFlags.isMultipleFillEventHistoryEnabled() && !forAugmentedAutofillOnly) {
678             mFillHistories.put(newSession.id, new FillEventHistory(sessionId, null));
679         }
680 
681         return newSession;
682     }
683 
684     /**
685      * Asserts the component is owned by the caller.
686      */
assertCallerLocked(@onNull ComponentName componentName, boolean compatMode)687     private void assertCallerLocked(@NonNull ComponentName componentName, boolean compatMode) {
688         final String packageName = componentName.getPackageName();
689         final PackageManager pm = getContext().getPackageManager();
690         final int callingUid = Binder.getCallingUid();
691         final int packageUid;
692         try {
693             packageUid = pm.getPackageUidAsUser(packageName, UserHandle.getCallingUserId());
694         } catch (NameNotFoundException e) {
695             throw new SecurityException("Could not verify UID for " + componentName);
696         }
697         if (callingUid != packageUid && !LocalServices.getService(ActivityManagerInternal.class)
698                 .hasRunningActivity(callingUid, packageName)) {
699             final String[] packages = pm.getPackagesForUid(callingUid);
700             final String callingPackage = packages != null ? packages[0] : "uid-" + callingUid;
701             Slog.w(TAG, "App (package=" + callingPackage + ", UID=" + callingUid
702                     + ") passed component (" + componentName + ") owned by UID " + packageUid);
703 
704             // NOTE: not using Helper.newLogMaker() because we don't have the session id
705             final LogMaker log = new LogMaker(MetricsEvent.AUTOFILL_FORGED_COMPONENT_ATTEMPT)
706                     .setPackageName(callingPackage)
707                     .addTaggedData(MetricsEvent.FIELD_AUTOFILL_SERVICE, getServicePackageName())
708                     .addTaggedData(MetricsEvent.FIELD_AUTOFILL_FORGED_COMPONENT_NAME,
709                             componentName == null ? "null" : componentName.flattenToShortString());
710             if (compatMode) {
711                 log.addTaggedData(MetricsEvent.FIELD_AUTOFILL_COMPAT_MODE, 1);
712             }
713             mMetricsLogger.write(log);
714 
715             throw new SecurityException("Invalid component: " + componentName);
716         }
717     }
718 
719     /**
720      * Restores a session after an activity was temporarily destroyed.
721      *
722      * @param sessionId The id of the session to restore
723      * @param uid UID of the process that tries to restore the session
724      * @param activityToken The new instance of the activity
725      * @param appCallback The callbacks to the activity
726      */
restoreSession(int sessionId, int uid, @NonNull IBinder activityToken, @NonNull IBinder appCallback)727     boolean restoreSession(int sessionId, int uid, @NonNull IBinder activityToken,
728             @NonNull IBinder appCallback) {
729         final Session session = mSessions.get(sessionId);
730 
731         if (session == null || uid != session.uid) {
732             return false;
733         } else {
734             session.switchActivity(activityToken, appCallback);
735             return true;
736         }
737     }
738 
739     /**
740      * Updates a session and returns whether it should be restarted.
741      */
742     @GuardedBy("mLock")
updateSessionLocked(int sessionId, int uid, AutofillId autofillId, Rect virtualBounds, AutofillValue value, int action, int flags)743     boolean updateSessionLocked(int sessionId, int uid, AutofillId autofillId, Rect virtualBounds,
744             AutofillValue value, int action, int flags) {
745         final Session session = mSessions.get(sessionId);
746         if (session == null || session.uid != uid) {
747             if ((flags & FLAG_MANUAL_REQUEST) != 0) {
748                 if (sDebug) {
749                     Slog.d(TAG, "restarting session " + sessionId + " due to manual request on "
750                             + autofillId);
751                 }
752                 return true;
753             }
754             if (sVerbose) {
755                 Slog.v(TAG, "updateSessionLocked(): session gone for " + sessionId
756                         + "(" + uid + ")");
757             }
758             return false;
759         }
760 
761         session.updateLocked(autofillId, virtualBounds, value, action, flags);
762         return false;
763     }
764 
callOnSessionDestroyed(int sessionId)765     void callOnSessionDestroyed(int sessionId) {
766         if (sVerbose) {
767             Slog.v(TAG, "removeSessionLocked(): removed " + sessionId);
768         }
769 
770         synchronized (mLock) {
771             FillEventHistory history = null;
772 
773             if (AutofillFeatureFlags.isMultipleFillEventHistoryEnabled()
774                     && mFillHistories != null) {
775                 history = mFillHistories.get(sessionId);
776                 mFillHistories.delete(sessionId);
777             }
778 
779             if (mInfo == null || mInfo.getServiceInfo() == null) {
780                 if (sVerbose) {
781                     Slog.v(TAG, "removeSessionLocked(): early return because mInfo is null");
782                 }
783                 return;
784             }
785 
786             if (mMaster == null) {
787                 if (sVerbose) {
788                     Slog.v(TAG, "removeSessionLocked(): early return because mMaster is null");
789                 }
790                 return;
791             }
792 
793             RemoteFillService remoteService =
794                     new RemoteFillService(
795                             getContext(),
796                             mInfo.getServiceInfo().getComponentName(),
797                             mUserId,
798                             /* callbacks= */ null,
799                             mMaster.isInstantServiceAllowed(),
800                             /* credentialAutofillService= */ null);
801 
802             remoteService.onSessionDestroyed(history);
803         }
804     }
805 
806     @GuardedBy("mLock")
removeSessionLocked(int sessionId)807     void removeSessionLocked(int sessionId) {
808         mSessions.remove(sessionId);
809         if (Flags.autofillSessionDestroyed()) {
810             mHandler.sendMessage(
811                     obtainMessage(
812                             AutofillManagerServiceImpl::callOnSessionDestroyed, this, sessionId));
813         }
814     }
815 
816     /**
817      * Ges the previous sessions asked to be kept alive in a given activity task.
818      *
819      * @param session session calling this method (so it's excluded from the result).
820      */
821     @Nullable
822     @GuardedBy("mLock")
getPreviousSessionsLocked(@onNull Session session)823     ArrayList<Session> getPreviousSessionsLocked(@NonNull Session session) {
824         final int size = mSessions.size();
825         ArrayList<Session> previousSessions = null;
826         for (int i = 0; i < size; i++) {
827             final Session previousSession = mSessions.valueAt(i);
828             if (previousSession.taskId == session.taskId && previousSession.id != session.id
829                     && (previousSession.getSaveInfoFlagsLocked() & SaveInfo.FLAG_DELAY_SAVE) != 0) {
830                 if (previousSessions == null) {
831                     previousSessions = new ArrayList<>(size);
832                 }
833                 previousSessions.add(previousSession);
834             }
835         }
836         // TODO(b/113281366): remove returned sessions / add CTS test
837         return previousSessions;
838     }
839 
handleSessionSave(Session session)840     void handleSessionSave(Session session) {
841         synchronized (mLock) {
842             if (mSessions.get(session.id) == null) {
843                 Slog.w(TAG, "handleSessionSave(): already gone: " + session.id);
844 
845                 return;
846             }
847             session.callSaveLocked();
848         }
849     }
850 
onPendingSaveUi(int operation, @NonNull IBinder token)851     void onPendingSaveUi(int operation, @NonNull IBinder token) {
852         if (sVerbose) Slog.v(TAG, "onPendingSaveUi(" + operation + "): " + token);
853         synchronized (mLock) {
854             final int sessionCount = mSessions.size();
855             for (int i = sessionCount - 1; i >= 0; i--) {
856                 final Session session = mSessions.valueAt(i);
857                 if (session.isSaveUiPendingForTokenLocked(token)) {
858                     session.onPendingSaveUi(operation, token);
859                     return;
860                 }
861             }
862         }
863         if (sDebug) {
864             Slog.d(TAG, "No pending Save UI for token " + token + " and operation "
865                     + DebugUtils.flagsToString(AutofillManager.class, "PENDING_UI_OPERATION_",
866                             operation));
867         }
868     }
869 
870     @GuardedBy("mLock")
notifyImeAnimationStart(int sessionId, long startTimeMs, int uid)871     public void notifyImeAnimationStart(int sessionId, long startTimeMs, int uid) {
872         if (!isEnabledLocked()) {
873             Slog.wtf(TAG, "Service not enabled");
874             return;
875         }
876         final Session session = mSessions.get(sessionId);
877         if (session == null || uid != session.uid) {
878             Slog.v(TAG, "notifyImeAnimationStart(): no session for "
879                     + sessionId + "(" + uid + ")");
880             return;
881         }
882         session.notifyImeAnimationStart(startTimeMs);
883     }
884 
885     @GuardedBy("mLock")
notifyImeAnimationEnd(int sessionId, long endTimeMs, int uid)886     public void notifyImeAnimationEnd(int sessionId, long endTimeMs, int uid) {
887         if (!isEnabledLocked()) {
888             Slog.wtf(TAG, "Service not enabled");
889             return;
890         }
891         final Session session = mSessions.get(sessionId);
892         if (session == null || uid != session.uid) {
893             Slog.v(TAG, "notifyImeAnimationEnd(): no session for "
894                     + sessionId + "(" + uid + ")");
895             return;
896         }
897         session.notifyImeAnimationEnd(endTimeMs);
898     }
899 
900     @GuardedBy("mLock")
901     @Override // from PerUserSystemService
handlePackageUpdateLocked(@onNull String packageName)902     protected void handlePackageUpdateLocked(@NonNull String packageName) {
903         final ServiceInfo serviceInfo = mFieldClassificationStrategy.getServiceInfo();
904         if (serviceInfo != null && serviceInfo.packageName.equals(packageName)) {
905             resetExtServiceLocked();
906         }
907     }
908 
909     @GuardedBy("mLock")
resetExtServiceLocked()910     void resetExtServiceLocked() {
911         if (sVerbose) Slog.v(TAG, "reset autofill service in ExtServices.");
912         mFieldClassificationStrategy.reset();
913         if (mRemoteInlineSuggestionRenderService != null) {
914             mRemoteInlineSuggestionRenderService.destroy();
915             mRemoteInlineSuggestionRenderService = null;
916         }
917     }
918 
919     @GuardedBy("mLock")
destroyLocked()920     void destroyLocked() {
921         if (sVerbose) Slog.v(TAG, "destroyLocked()");
922 
923         resetExtServiceLocked();
924 
925         final int numSessions = mSessions.size();
926         final ArraySet<RemoteFillService> remoteFillServices = new ArraySet<>(numSessions);
927         for (int i = 0; i < numSessions; i++) {
928             final RemoteFillService remoteFillService = mSessions.valueAt(i).destroyLocked();
929             if (remoteFillService != null) {
930                 remoteFillServices.add(remoteFillService);
931             }
932         }
933         mSessions.clear();
934         if (AutofillFeatureFlags.isMultipleFillEventHistoryEnabled()) {
935             mFillHistories.clear();
936         }
937 
938         for (int i = 0; i < remoteFillServices.size(); i++) {
939             remoteFillServices.valueAt(i).destroy();
940         }
941 
942         sendStateToClients(/* resetclient=*/ true);
943         if (mClients != null) {
944             mClients.kill();
945             mClients = null;
946         }
947     }
948 
949     /**
950      * Initializes the last fill selection after an autofill service returned a new
951      * {@link FillResponse}.
952      */
953     @GuardedBy("mLock")
setLastResponseLocked(int sessionId, @NonNull FillResponse response)954     void setLastResponseLocked(int sessionId, @NonNull FillResponse response) {
955             mEventHistory = new FillEventHistory(sessionId, response.getClientState());
956     }
957 
setLastAugmentedAutofillResponse(int sessionId)958     void setLastAugmentedAutofillResponse(int sessionId) {
959         synchronized (mLock) {
960             mAugmentedAutofillEventHistory = new FillEventHistory(sessionId, /* clientState= */
961                     null);
962         }
963     }
964 
965     /**
966      * Resets the last fill selection.
967      */
resetLastResponse()968     void resetLastResponse() {
969         synchronized (mLock) {
970             mEventHistory = null;
971         }
972     }
973 
resetLastAugmentedAutofillResponse()974     void resetLastAugmentedAutofillResponse() {
975         synchronized (mLock) {
976             mAugmentedAutofillEventHistory = null;
977         }
978     }
979 
980     @GuardedBy("mLock")
isValidEventLocked(String method, int sessionId)981     private boolean isValidEventLocked(String method, int sessionId) {
982         if (mEventHistory == null) {
983             Slog.w(TAG, method + ": not logging event because history is null");
984             return false;
985         }
986         if (sessionId != mEventHistory.getSessionId()) {
987             if (sDebug) {
988                 Slog.d(TAG, method + ": not logging event for session " + sessionId
989                         + " because tracked session is " + mEventHistory.getSessionId());
990             }
991             return false;
992         }
993         return true;
994     }
995 
996     @GuardedBy("mLock")
addEventToHistory(String eventName, int sessionId, Event event)997     void addEventToHistory(String eventName, int sessionId, Event event) {
998         // For the singleton filleventhistory
999         if (isValidEventLocked(eventName, sessionId)) {
1000             mEventHistory.addEvent(event);
1001         }
1002 
1003         if (AutofillFeatureFlags.isMultipleFillEventHistoryEnabled()) {
1004             FillEventHistory history = mFillHistories.get(sessionId);
1005             if (history != null) {
1006                 history.addEvent(event);
1007             } else {
1008                 if (sVerbose) {
1009                     Slog.v(TAG, eventName
1010                             + " not logged because FillEventHistory is not tracked for: "
1011                             + sessionId);
1012                 }
1013             }
1014         }
1015     }
1016 
1017     /**
1018      * Updates the last fill selection when an authentication was selected.
1019      */
setAuthenticationSelected(int sessionId, @Nullable Bundle clientState, int uiType, @Nullable AutofillId focusedId, boolean shouldAdd)1020     void setAuthenticationSelected(int sessionId, @Nullable Bundle clientState,
1021             int uiType, @Nullable AutofillId focusedId, boolean shouldAdd) {
1022         synchronized (mLock) {
1023 
1024             String methodName = "setAuthenticationSelected()";
1025 
1026             if (!shouldAdd) {
1027                 if (sVerbose) {
1028                     Slog.v(TAG, methodName + " not logged because shouldAdd is false");
1029                 }
1030                 return;
1031             }
1032 
1033             Event event =
1034                     new Event(
1035                             Event.TYPE_AUTHENTICATION_SELECTED,
1036                             null,
1037                             clientState,
1038                             null,
1039                             null,
1040                             null,
1041                             null,
1042                             null,
1043                             null,
1044                             null,
1045                             null,
1046                             NO_SAVE_UI_REASON_NONE,
1047                             uiType,
1048                             focusedId);
1049 
1050             addEventToHistory(methodName, sessionId, event);
1051         }
1052     }
1053 
1054     /** Updates the last fill selection when a dataset authentication was selected. */
logDatasetAuthenticationSelected( @ullable String selectedDataset, int sessionId, @Nullable Bundle clientState, int uiType, @Nullable AutofillId focusedId, boolean shouldAdd)1055     void logDatasetAuthenticationSelected(
1056             @Nullable String selectedDataset,
1057             int sessionId,
1058             @Nullable Bundle clientState,
1059             int uiType,
1060             @Nullable AutofillId focusedId,
1061             boolean shouldAdd) {
1062         synchronized (mLock) {
1063             String methodName = "logDatasetAuthenticationSelected()";
1064 
1065             if (!shouldAdd) {
1066                 if (sVerbose) {
1067                     Slog.v(TAG, methodName + " not logged because shouldAdd is false");
1068                 }
1069                 return;
1070             }
1071 
1072             Event event = new Event(Event.TYPE_DATASET_AUTHENTICATION_SELECTED, selectedDataset,
1073                                 clientState, null, null, null, null, null, null, null, null,
1074                                 NO_SAVE_UI_REASON_NONE, uiType, focusedId);
1075             addEventToHistory(methodName, sessionId, event);
1076         }
1077     }
1078 
1079     /**
1080      * Updates the last fill selection when an save Ui is shown.
1081      */
logSaveShown(int sessionId, @Nullable Bundle clientState, boolean shouldAdd)1082     void logSaveShown(int sessionId, @Nullable Bundle clientState, boolean shouldAdd) {
1083         synchronized (mLock) {
1084             String methodName = "logSaveShown()";
1085 
1086             if (!shouldAdd) {
1087                 if (sVerbose) {
1088                     Slog.v(TAG, methodName + " not logged because shouldAdd is false");
1089                 }
1090                 return;
1091             }
1092 
1093             Event event = new Event(Event.TYPE_SAVE_SHOWN, null, clientState, null,
1094                         null, null, null, null, null, null, null, /* focusedId= */ null);
1095 
1096             addEventToHistory(methodName, sessionId, event);
1097         }
1098     }
1099 
1100     /** Updates the last fill response when a dataset was selected. */
logDatasetSelected( @ullable String selectedDataset, int sessionId, @Nullable Bundle clientState, int uiType, @Nullable AutofillId focusedId, boolean shouldAdd)1101     void logDatasetSelected(
1102             @Nullable String selectedDataset,
1103             int sessionId,
1104             @Nullable Bundle clientState,
1105             int uiType,
1106             @Nullable AutofillId focusedId,
1107             boolean shouldAdd) {
1108         synchronized (mLock) {
1109             String methodName = "logDatasetSelected()";
1110 
1111             if (!shouldAdd) {
1112                 if (sVerbose) {
1113                     Slog.v(TAG, methodName + " not logged because shouldAdd is false");
1114                 }
1115                 return;
1116             }
1117 
1118             Event event = new Event(Event.TYPE_DATASET_SELECTED, selectedDataset, clientState, null,
1119                                 null, null, null, null, null, null, null, NO_SAVE_UI_REASON_NONE,
1120                                 uiType, focusedId);
1121             addEventToHistory(methodName, sessionId, event);
1122         }
1123     }
1124 
1125     /**
1126      * Updates the last fill response when a dataset is shown.
1127      */
logDatasetShown(int sessionId, @Nullable Bundle clientState, int uiType, @Nullable AutofillId focusedId, boolean shouldAdd)1128     void logDatasetShown(int sessionId, @Nullable Bundle clientState, int uiType,
1129             @Nullable AutofillId focusedId, boolean shouldAdd) {
1130         synchronized (mLock) {
1131             String methodName = "logDatasetShown()";
1132 
1133             if (!shouldAdd) {
1134                 if (sVerbose) {
1135                     Slog.v(TAG, methodName + " not logged because shouldAdd is false");
1136                 }
1137                 return;
1138             }
1139 
1140             Event event = new Event(Event.TYPE_DATASETS_SHOWN, null, clientState, null, null, null,
1141                                 null, null, null, null, null, NO_SAVE_UI_REASON_NONE,
1142                                 uiType, focusedId);
1143             addEventToHistory(methodName, sessionId, event);
1144         }
1145     }
1146 
logViewEnteredForHistory( int sessionId, @Nullable Bundle clientState, FillEventHistory history, @Nullable AutofillId focusedId)1147     void logViewEnteredForHistory(
1148             int sessionId,
1149             @Nullable Bundle clientState,
1150             FillEventHistory history,
1151             @Nullable AutofillId focusedId) {
1152         if (history.getEvents() != null) {
1153             // Do not log this event more than once
1154             for (Event event : history.getEvents()) {
1155                 if (event.getType() == Event.TYPE_VIEW_REQUESTED_AUTOFILL) {
1156                     if (sVerbose) {
1157                         Slog.v(TAG, "logViewEntered: already logged TYPE_VIEW_REQUESTED_AUTOFILL");
1158                     }
1159                     return;
1160                 }
1161             }
1162         }
1163 
1164         history.addEvent(
1165                 new Event(Event.TYPE_VIEW_REQUESTED_AUTOFILL, null, clientState, null,
1166                         null, null, null, null, null, null, null, focusedId));
1167     }
1168 
1169     /**
1170      * Updates the last fill response when a view was entered.
1171      */
logViewEntered(int sessionId, @Nullable Bundle clientState, @Nullable AutofillId focusedId, boolean shouldAdd)1172     void logViewEntered(int sessionId, @Nullable Bundle clientState,
1173             @Nullable AutofillId focusedId, boolean shouldAdd) {
1174         synchronized (mLock) {
1175             String methodName = "logViewEntered()";
1176 
1177             if (!shouldAdd) {
1178                 if (sVerbose) {
1179                     Slog.v(TAG, methodName + " not logged because shouldAdd is false");
1180                 }
1181                 return;
1182             }
1183 
1184             // This log does not call addEventToHistory() because each distinct FillEventHistory
1185             // can only contain 1 TYPE_VIEW_REQUESTED_AUTOFILL event. Therefore, checking both
1186             // the singleton FillEventHistory and the per Session FillEventHistory is necessary
1187 
1188             if (isValidEventLocked(methodName, sessionId)) {
1189                 logViewEnteredForHistory(sessionId, clientState, mEventHistory, focusedId);
1190             }
1191 
1192             if (AutofillFeatureFlags.isMultipleFillEventHistoryEnabled()) {
1193                 FillEventHistory history = mFillHistories.get(sessionId);
1194                 if (history != null) {
1195                     logViewEnteredForHistory(sessionId, clientState, history, focusedId);
1196                 }
1197             }
1198         }
1199     }
1200 
logAugmentedAutofillAuthenticationSelected(int sessionId, @Nullable String selectedDataset, @Nullable Bundle clientState)1201     void logAugmentedAutofillAuthenticationSelected(int sessionId, @Nullable String selectedDataset,
1202             @Nullable Bundle clientState) {
1203         synchronized (mLock) {
1204             if (mAugmentedAutofillEventHistory == null
1205                     || mAugmentedAutofillEventHistory.getSessionId() != sessionId) {
1206                 return;
1207             }
1208             mAugmentedAutofillEventHistory.addEvent(
1209                     new Event(Event.TYPE_DATASET_AUTHENTICATION_SELECTED, selectedDataset,
1210                             clientState, null, null, null, null, null, null, null, null,
1211                             /* focusedId= */ null));
1212         }
1213     }
1214 
logAugmentedAutofillSelected(int sessionId, @Nullable String suggestionId, @Nullable Bundle clientState)1215     void logAugmentedAutofillSelected(int sessionId, @Nullable String suggestionId,
1216             @Nullable Bundle clientState) {
1217         synchronized (mLock) {
1218             if (mAugmentedAutofillEventHistory == null
1219                     || mAugmentedAutofillEventHistory.getSessionId() != sessionId) {
1220                 return;
1221             }
1222             mAugmentedAutofillEventHistory.addEvent(
1223                     new Event(Event.TYPE_DATASET_SELECTED, suggestionId, clientState, null, null,
1224                             null, null, null, null, null, null, /* focusedId= */ null));
1225         }
1226     }
1227 
logAugmentedAutofillShown(int sessionId, @Nullable Bundle clientState)1228     void logAugmentedAutofillShown(int sessionId, @Nullable Bundle clientState) {
1229         synchronized (mLock) {
1230             if (mAugmentedAutofillEventHistory == null
1231                     || mAugmentedAutofillEventHistory.getSessionId() != sessionId) {
1232                 return;
1233             }
1234             // Augmented Autofill only logs for inline now, so set UI_TYPE_INLINE here.
1235             // Ideally should not hardcode here and should also log for menu presentation.
1236             mAugmentedAutofillEventHistory.addEvent(
1237                     new Event(Event.TYPE_DATASETS_SHOWN, null, clientState, null, null, null,
1238                             null, null, null, null, null, NO_SAVE_UI_REASON_NONE,
1239                             UI_TYPE_INLINE, /* focusedId= */ null));
1240 
1241         }
1242     }
1243 
1244     /**
1245      * Updates the last fill response when an autofill context is committed.
1246      */
1247     @GuardedBy("mLock")
logContextCommittedLocked(int sessionId, @Nullable Bundle clientState, @Nullable ArrayList<String> selectedDatasets, @Nullable ArraySet<String> ignoredDatasets, @Nullable ArrayList<AutofillId> changedFieldIds, @Nullable ArrayList<String> changedDatasetIds, @Nullable ArrayList<AutofillId> manuallyFilledFieldIds, @Nullable ArrayList<ArrayList<String>> manuallyFilledDatasetIds, @NonNull ComponentName appComponentName, boolean compatMode, boolean shouldAdd)1248     void logContextCommittedLocked(int sessionId, @Nullable Bundle clientState,
1249             @Nullable ArrayList<String> selectedDatasets,
1250             @Nullable ArraySet<String> ignoredDatasets,
1251             @Nullable ArrayList<AutofillId> changedFieldIds,
1252             @Nullable ArrayList<String> changedDatasetIds,
1253             @Nullable ArrayList<AutofillId> manuallyFilledFieldIds,
1254             @Nullable ArrayList<ArrayList<String>> manuallyFilledDatasetIds,
1255             @NonNull ComponentName appComponentName, boolean compatMode, boolean shouldAdd) {
1256         logContextCommittedLocked(sessionId, clientState, selectedDatasets, ignoredDatasets,
1257                 changedFieldIds, changedDatasetIds, manuallyFilledFieldIds,
1258                 manuallyFilledDatasetIds, /* detectedFieldIdsList= */ null,
1259                 /* detectedFieldClassificationsList= */ null, appComponentName, compatMode,
1260                 Event.NO_SAVE_UI_REASON_NONE, shouldAdd);
1261     }
1262 
1263     @GuardedBy("mLock")
logContextCommittedLocked(int sessionId, @Nullable Bundle clientState, @Nullable ArrayList<String> selectedDatasets, @Nullable ArraySet<String> ignoredDatasets, @Nullable ArrayList<AutofillId> changedFieldIds, @Nullable ArrayList<String> changedDatasetIds, @Nullable ArrayList<AutofillId> manuallyFilledFieldIds, @Nullable ArrayList<ArrayList<String>> manuallyFilledDatasetIds, @Nullable ArrayList<AutofillId> detectedFieldIdsList, @Nullable ArrayList<FieldClassification> detectedFieldClassificationsList, @NonNull ComponentName appComponentName, boolean compatMode, @NoSaveReason int saveDialogNotShowReason, boolean shouldAdd)1264     void logContextCommittedLocked(int sessionId, @Nullable Bundle clientState,
1265             @Nullable ArrayList<String> selectedDatasets,
1266             @Nullable ArraySet<String> ignoredDatasets,
1267             @Nullable ArrayList<AutofillId> changedFieldIds,
1268             @Nullable ArrayList<String> changedDatasetIds,
1269             @Nullable ArrayList<AutofillId> manuallyFilledFieldIds,
1270             @Nullable ArrayList<ArrayList<String>> manuallyFilledDatasetIds,
1271             @Nullable ArrayList<AutofillId> detectedFieldIdsList,
1272             @Nullable ArrayList<FieldClassification> detectedFieldClassificationsList,
1273             @NonNull ComponentName appComponentName, boolean compatMode,
1274             @NoSaveReason int saveDialogNotShowReason,
1275             boolean shouldAdd) {
1276 
1277         String methodName = "logContextCommittedLocked()";
1278 
1279         if (!shouldAdd) {
1280             if (sVerbose) {
1281                 Slog.v(TAG, methodName + " not logged because shouldAdd is false");
1282             }
1283             return;
1284         }
1285 
1286         if (sVerbose) {
1287                 Slog.v(TAG, "logContextCommitted() with FieldClassification: id=" + sessionId
1288                         + ", selectedDatasets=" + selectedDatasets
1289                         + ", ignoredDatasetIds=" + ignoredDatasets
1290                         + ", changedAutofillIds=" + changedFieldIds
1291                         + ", changedDatasetIds=" + changedDatasetIds
1292                         + ", manuallyFilledFieldIds=" + manuallyFilledFieldIds
1293                         + ", detectedFieldIds=" + detectedFieldIdsList
1294                         + ", detectedFieldClassifications=" + detectedFieldClassificationsList
1295                         + ", appComponentName=" + appComponentName.toShortString()
1296                         + ", compatMode=" + compatMode
1297                         + ", saveDialogNotShowReason=" + saveDialogNotShowReason);
1298         }
1299 
1300         AutofillId[] detectedFieldsIds = null;
1301         FieldClassification[] detectedFieldClassifications = null;
1302         if (detectedFieldIdsList != null) {
1303             detectedFieldsIds = new AutofillId[detectedFieldIdsList.size()];
1304             detectedFieldIdsList.toArray(detectedFieldsIds);
1305             detectedFieldClassifications =
1306                     new FieldClassification[detectedFieldClassificationsList.size()];
1307             detectedFieldClassificationsList.toArray(detectedFieldClassifications);
1308 
1309             final int numberFields = detectedFieldsIds.length;
1310             int totalSize = 0;
1311             float totalScore = 0;
1312             for (int i = 0; i < numberFields; i++) {
1313                 final FieldClassification fc = detectedFieldClassifications[i];
1314                 final List<Match> matches = fc.getMatches();
1315                 final int size = matches.size();
1316                 totalSize += size;
1317                 for (int j = 0; j < size; j++) {
1318                     totalScore += matches.get(j).getScore();
1319                 }
1320             }
1321 
1322             final int averageScore = (int) ((totalScore * 100) / totalSize);
1323             mMetricsLogger.write(
1324                     Helper.newLogMaker(
1325                                     MetricsEvent.AUTOFILL_FIELD_CLASSIFICATION_MATCHES,
1326                                     appComponentName,
1327                                     getServicePackageName(),
1328                                     sessionId,
1329                                     compatMode)
1330                             .setCounterValue(numberFields)
1331                             .addTaggedData(MetricsEvent.FIELD_AUTOFILL_MATCH_SCORE, averageScore));
1332         }
1333         Event event =
1334                 new Event(
1335                         Event.TYPE_CONTEXT_COMMITTED,
1336                         null,
1337                         clientState,
1338                         selectedDatasets,
1339                         ignoredDatasets,
1340                         changedFieldIds,
1341                         changedDatasetIds,
1342                         manuallyFilledFieldIds,
1343                         manuallyFilledDatasetIds,
1344                         detectedFieldsIds,
1345                         detectedFieldClassifications,
1346                         saveDialogNotShowReason,
1347                         /* focusedId= */ null);
1348 
1349         addEventToHistory(methodName, sessionId, event);
1350     }
1351 
1352     /**
1353      * Gets the fill event history.
1354      *
1355      * @param callingUid The calling uid
1356      * @return The history for the autofill or the augmented autofill events depending on the {@code
1357      *     callingUid}, or {@code null} if there is none.
1358      * @deprecated Use {@link
1359      *     android.service.autofill.AutofillService#onSessionDestroyed(FillEventHistory)}
1360      */
getFillEventHistory(int callingUid)1361     FillEventHistory getFillEventHistory(int callingUid) {
1362         synchronized (mLock) {
1363             if (mEventHistory != null
1364                     && isCalledByServiceLocked("getFillEventHistory", callingUid)) {
1365                 return mEventHistory;
1366             }
1367             if (mAugmentedAutofillEventHistory != null && isCalledByAugmentedAutofillServiceLocked(
1368                     "getFillEventHistory", callingUid)) {
1369                 return mAugmentedAutofillEventHistory;
1370             }
1371         }
1372         return null;
1373     }
1374 
1375     // Called by Session - does not need to check uid
getUserData()1376     UserData getUserData() {
1377         synchronized (mLock) {
1378             return mUserData;
1379         }
1380     }
1381 
1382     // Called by AutofillManager
getUserData(int callingUid)1383     UserData getUserData(int callingUid) {
1384         synchronized (mLock) {
1385             if (isCalledByServiceLocked("getUserData", callingUid)) {
1386                 return mUserData;
1387             }
1388         }
1389         return null;
1390     }
1391 
1392     // Called by AutofillManager
setUserData(int callingUid, UserData userData)1393     void setUserData(int callingUid, UserData userData) {
1394         synchronized (mLock) {
1395             if (!isCalledByServiceLocked("setUserData", callingUid)) {
1396                 return;
1397             }
1398             mUserData = userData;
1399             // Log it
1400             final int numberFields = mUserData == null ? 0: mUserData.getCategoryIds().length;
1401             // NOTE: contrary to most metrics, the service name is logged as the main package name
1402             // here, not as MetricsEvent.FIELD_AUTOFILL_SERVICE
1403             mMetricsLogger.write(new LogMaker(MetricsEvent.AUTOFILL_USERDATA_UPDATED)
1404                     .setPackageName(getServicePackageName())
1405                     .addTaggedData(MetricsEvent.FIELD_AUTOFILL_NUM_VALUES, numberFields));
1406         }
1407     }
1408 
1409     @GuardedBy("mLock")
isCalledByServiceLocked(@onNull String methodName, int callingUid)1410     private boolean isCalledByServiceLocked(@NonNull String methodName, int callingUid) {
1411         final int serviceUid = getServiceUidLocked();
1412         if (serviceUid != callingUid) {
1413             Slog.w(TAG, methodName + "() called by UID " + callingUid
1414                     + ", but service UID is " + serviceUid);
1415             return false;
1416         }
1417         return true;
1418     }
1419 
1420     @GuardedBy("mLock")
getSupportedSmartSuggestionModesLocked()1421     @SmartSuggestionMode int getSupportedSmartSuggestionModesLocked() {
1422         return mMaster.getSupportedSmartSuggestionModesLocked();
1423     }
1424 
1425     @Override
1426     @GuardedBy("mLock")
dumpLocked(String prefix, PrintWriter pw)1427     protected void dumpLocked(String prefix, PrintWriter pw) {
1428         super.dumpLocked(prefix, pw);
1429 
1430         final String prefix2 = prefix + "  ";
1431 
1432         pw.print(prefix); pw.print("UID: "); pw.println(getServiceUidLocked());
1433         pw.print(prefix); pw.print("Autofill Service Info: ");
1434         if (mInfo == null) {
1435             pw.println("N/A");
1436         } else {
1437             pw.println();
1438             mInfo.dump(prefix2, pw);
1439         }
1440         pw.print(prefix); pw.print("Default component: "); pw.println(getContext()
1441                 .getString(R.string.config_defaultAutofillService));
1442         pw.println();
1443 
1444         pw.print(prefix); pw.println("mAugmentedAutofillName: ");
1445         pw.print(prefix2); mMaster.mAugmentedAutofillResolver.dumpShort(pw, mUserId);
1446         pw.println();
1447         if (mRemoteAugmentedAutofillService != null) {
1448             pw.print(prefix); pw.println("RemoteAugmentedAutofillService: ");
1449             mRemoteAugmentedAutofillService.dump(prefix2, pw);
1450         }
1451         if (mRemoteAugmentedAutofillServiceInfo != null) {
1452             pw.print(prefix); pw.print("RemoteAugmentedAutofillServiceInfo: ");
1453             pw.println(mRemoteAugmentedAutofillServiceInfo);
1454         }
1455         pw.println();
1456 
1457         pw.print(prefix); pw.println("mFieldClassificationService for system detection");
1458         pw.print(prefix2); pw.print("Default component: "); pw.println(getContext()
1459                 .getString(R.string.config_defaultFieldClassificationService));
1460         pw.print(prefix2); mMaster.mFieldClassificationResolver.dumpShort(pw, mUserId);
1461         pw.println();
1462 
1463         if (mRemoteFieldClassificationService != null) {
1464             pw.print(prefix); pw.println("RemoteFieldClassificationService: ");
1465             mRemoteFieldClassificationService.dump(prefix2, pw);
1466         } else {
1467             pw.print(prefix); pw.println("mRemoteFieldClassificationService: null");
1468         }
1469         if (mRemoteFieldClassificationServiceInfo != null) {
1470             pw.print(prefix); pw.print("RemoteFieldClassificationServiceInfo: ");
1471             pw.println(mRemoteFieldClassificationServiceInfo);
1472         } else {
1473             pw.print(prefix); pw.println("mRemoteFieldClassificationServiceInfo: null");
1474         }
1475         pw.println();
1476 
1477         pw.print(prefix); pw.print("Field classification enabled: ");
1478             pw.println(isFieldClassificationEnabledLocked());
1479         pw.print(prefix); pw.print("Compat pkgs: ");
1480         final ArrayMap<String, Long> compatPkgs = getCompatibilityPackagesLocked();
1481         if (compatPkgs == null) {
1482             pw.println("N/A");
1483         } else {
1484             pw.println(compatPkgs);
1485         }
1486         pw.print(prefix); pw.print("Inline Suggestions Enabled: ");
1487         pw.println(isInlineSuggestionsEnabledLocked());
1488         pw.print(prefix); pw.print("Last prune: "); pw.println(mLastPrune);
1489 
1490         mDisabledInfoCache.dump(mUserId, prefix, pw);
1491 
1492         final int size = mSessions.size();
1493         if (size == 0) {
1494             pw.print(prefix); pw.println("No sessions");
1495         } else {
1496             pw.print(prefix); pw.print(size); pw.println(" sessions:");
1497             for (int i = 0; i < size; i++) {
1498                 pw.print(prefix); pw.print("#"); pw.println(i + 1);
1499                 mSessions.valueAt(i).dumpLocked(prefix2, pw);
1500             }
1501         }
1502 
1503         pw.print(prefix); pw.print("Clients: ");
1504         if (mClients == null) {
1505             pw.println("N/A");
1506         } else {
1507             pw.println();
1508             mClients.dump(pw, prefix2);
1509         }
1510 
1511         if (mEventHistory == null || mEventHistory.getEvents() == null
1512                 || mEventHistory.getEvents().size() == 0) {
1513             pw.print(prefix); pw.println("No event on last fill response");
1514         } else {
1515             pw.print(prefix); pw.println("Events of last fill response:");
1516             pw.print(prefix);
1517 
1518             int numEvents = mEventHistory.getEvents().size();
1519             for (int i = 0; i < numEvents; i++) {
1520                 final Event event = mEventHistory.getEvents().get(i);
1521                 pw.println("  " + i + ": eventType=" + event.getType() + " datasetId="
1522                         + event.getDatasetId());
1523             }
1524         }
1525 
1526         pw.print(prefix); pw.print("User data: ");
1527         if (mUserData == null) {
1528             pw.println("N/A");
1529         } else {
1530             pw.println();
1531             mUserData.dump(prefix2, pw);
1532         }
1533 
1534         pw.print(prefix); pw.println("Field Classification strategy: ");
1535         mFieldClassificationStrategy.dump(prefix2, pw);
1536     }
1537 
1538     @GuardedBy("mLock")
forceRemoveAllSessionsLocked()1539     void forceRemoveAllSessionsLocked() {
1540         final int sessionCount = mSessions.size();
1541         if (sessionCount == 0) {
1542             mUi.destroyAll(null, null, false);
1543             return;
1544         }
1545 
1546         for (int i = sessionCount - 1; i >= 0; i--) {
1547             mSessions.valueAt(i).forceRemoveFromServiceLocked();
1548         }
1549     }
1550 
1551     @GuardedBy("mLock")
forceRemoveForAugmentedOnlySessionsLocked()1552     void forceRemoveForAugmentedOnlySessionsLocked() {
1553         final int sessionCount = mSessions.size();
1554         for (int i = sessionCount - 1; i >= 0; i--) {
1555             mSessions.valueAt(i).forceRemoveFromServiceIfForAugmentedOnlyLocked();
1556         }
1557     }
1558 
1559     /**
1560      * This method is called exclusively in response to {@code Intent.ACTION_CLOSE_SYSTEM_DIALOGS}.
1561      * The method removes all sessions that are finished but showing SaveUI due to how SaveUI is
1562      * managed (see b/64940307). Otherwise it will remove any augmented autofill generated windows.
1563      */
1564     // TODO(b/64940307): remove this method if SaveUI is refactored to be attached on activities
1565     @GuardedBy("mLock")
forceRemoveFinishedSessionsLocked()1566     void forceRemoveFinishedSessionsLocked() {
1567         final int sessionCount = mSessions.size();
1568         for (int i = sessionCount - 1; i >= 0; i--) {
1569             final Session session = mSessions.valueAt(i);
1570             if (session.isSaveUiShowingLocked()) {
1571                 if (sDebug) Slog.d(TAG, "destroyFinishedSessionsLocked(): " + session.id);
1572                 session.forceRemoveFromServiceLocked();
1573             } else {
1574                 session.destroyAugmentedAutofillWindowsLocked();
1575             }
1576         }
1577     }
1578 
1579     @GuardedBy("mLock")
listSessionsLocked(ArrayList<String> output)1580     void listSessionsLocked(ArrayList<String> output) {
1581         final int numSessions = mSessions.size();
1582         if (numSessions <= 0) return;
1583 
1584         final String fmt = "%d:%s:%s";
1585         for (int i = 0; i < numSessions; i++) {
1586             final int id = mSessions.keyAt(i);
1587             final String service = mInfo == null
1588                     ? "no_svc"
1589                     : mInfo.getServiceInfo().getComponentName().flattenToShortString();
1590             final String augmentedService = mRemoteAugmentedAutofillServiceInfo == null
1591                     ? "no_aug"
1592                     : mRemoteAugmentedAutofillServiceInfo.getComponentName().flattenToShortString();
1593             output.add(String.format(fmt, id, service, augmentedService));
1594         }
1595     }
1596 
1597     @GuardedBy("mLock")
getCompatibilityPackagesLocked()1598     @Nullable ArrayMap<String, Long> getCompatibilityPackagesLocked() {
1599         if (mInfo != null) {
1600             return mInfo.getCompatibilityPackages();
1601         }
1602         return null;
1603     }
1604 
1605     @GuardedBy("mLock")
isInlineSuggestionsEnabledLocked()1606     boolean isInlineSuggestionsEnabledLocked() {
1607         if (mInfo != null) {
1608             return mInfo.isInlineSuggestionsEnabled();
1609         }
1610         return false;
1611     }
1612 
1613     @GuardedBy("mLock")
requestSavedPasswordCount(IResultReceiver receiver)1614     void requestSavedPasswordCount(IResultReceiver receiver) {
1615         RemoteFillService remoteService =
1616                 new RemoteFillService(
1617                         getContext(), mInfo.getServiceInfo().getComponentName(), mUserId,
1618                         /* callbacks= */ null, mMaster.isInstantServiceAllowed(),
1619                         mMaster.mCredentialAutofillService);
1620         remoteService.onSavedPasswordCountRequest(receiver);
1621     }
1622 
1623     @GuardedBy("mLock")
getRemoteAugmentedAutofillServiceLocked()1624     @Nullable RemoteAugmentedAutofillService getRemoteAugmentedAutofillServiceLocked() {
1625         if (mRemoteAugmentedAutofillService == null) {
1626             final String serviceName = mMaster.mAugmentedAutofillResolver.getServiceName(mUserId);
1627             if (serviceName == null) {
1628                 if (mMaster.verbose) {
1629                     Slog.v(TAG, "getRemoteAugmentedAutofillServiceLocked(): not set");
1630                 }
1631                 return null;
1632             }
1633             final Pair<ServiceInfo, ComponentName> pair = RemoteAugmentedAutofillService
1634                     .getComponentName(serviceName, mUserId,
1635                             mMaster.mAugmentedAutofillResolver.isTemporary(mUserId));
1636             if (pair == null) return null;
1637 
1638             mRemoteAugmentedAutofillServiceInfo = pair.first;
1639             final ComponentName componentName = pair.second;
1640             if (sVerbose) {
1641                 Slog.v(TAG, "getRemoteAugmentedAutofillServiceLocked(): " + componentName);
1642             }
1643 
1644             final RemoteAugmentedAutofillServiceCallbacks callbacks =
1645                     new RemoteAugmentedAutofillServiceCallbacks() {
1646                         @Override
1647                         public void resetLastResponse() {
1648                             AutofillManagerServiceImpl.this.resetLastAugmentedAutofillResponse();
1649                         }
1650 
1651                         @Override
1652                         public void setLastResponse(int sessionId) {
1653                             AutofillManagerServiceImpl.this.setLastAugmentedAutofillResponse(
1654                                     sessionId);
1655                         }
1656 
1657                         @Override
1658                         public void logAugmentedAutofillShown(int sessionId, Bundle clientState) {
1659                             AutofillManagerServiceImpl.this.logAugmentedAutofillShown(sessionId,
1660                                     clientState);
1661                         }
1662 
1663                         @Override
1664                         public void logAugmentedAutofillSelected(int sessionId,
1665                                 String suggestionId, Bundle clientState) {
1666                             AutofillManagerServiceImpl.this.logAugmentedAutofillSelected(sessionId,
1667                                     suggestionId, clientState);
1668                         }
1669 
1670                         @Override
1671                         public void logAugmentedAutofillAuthenticationSelected(int sessionId,
1672                                 String suggestionId, Bundle clientState) {
1673                             AutofillManagerServiceImpl.this
1674                                     .logAugmentedAutofillAuthenticationSelected(
1675                                             sessionId, suggestionId, clientState);
1676                         }
1677 
1678                         @Override
1679                         public void onServiceDied(@NonNull RemoteAugmentedAutofillService service) {
1680                             Slog.w(TAG, "remote augmented autofill service died");
1681                             final RemoteAugmentedAutofillService remoteService =
1682                                     mRemoteAugmentedAutofillService;
1683                             if (remoteService != null) {
1684                                 remoteService.unbind();
1685                             }
1686                             mRemoteAugmentedAutofillService = null;
1687                         }
1688                     };
1689             final int serviceUid = mRemoteAugmentedAutofillServiceInfo.applicationInfo.uid;
1690             mRemoteAugmentedAutofillService = new RemoteAugmentedAutofillService(getContext(),
1691                     serviceUid, componentName,
1692                     mUserId, callbacks, mMaster.isInstantServiceAllowed(),
1693                     mMaster.verbose, mMaster.mAugmentedServiceIdleUnbindTimeoutMs,
1694                     mMaster.mAugmentedServiceRequestTimeoutMs);
1695         }
1696 
1697         return mRemoteAugmentedAutofillService;
1698     }
1699 
1700     @GuardedBy("mLock")
getRemoteAugmentedAutofillServiceIfCreatedLocked()1701     @Nullable RemoteAugmentedAutofillService getRemoteAugmentedAutofillServiceIfCreatedLocked() {
1702         return mRemoteAugmentedAutofillService;
1703     }
1704 
1705     /**
1706      * Called when the {@link AutofillManagerService#mAugmentedAutofillResolver}
1707      * changed (among other places).
1708      */
updateRemoteAugmentedAutofillService()1709     void updateRemoteAugmentedAutofillService() {
1710         synchronized (mLock) {
1711             if (mRemoteAugmentedAutofillService != null) {
1712                 if (sVerbose) {
1713                     Slog.v(TAG, "updateRemoteAugmentedAutofillService(): "
1714                             + "destroying old remote service");
1715                 }
1716                 forceRemoveForAugmentedOnlySessionsLocked();
1717                 mRemoteAugmentedAutofillService.unbind();
1718                 mRemoteAugmentedAutofillService = null;
1719                 mRemoteAugmentedAutofillServiceInfo = null;
1720                 resetAugmentedAutofillWhitelistLocked();
1721             }
1722 
1723             final boolean available = isAugmentedAutofillServiceAvailableLocked();
1724             if (sVerbose) Slog.v(TAG, "updateRemoteAugmentedAutofillService(): " + available);
1725 
1726             if (available) {
1727                 mRemoteAugmentedAutofillService = getRemoteAugmentedAutofillServiceLocked();
1728             }
1729         }
1730     }
1731 
isAugmentedAutofillServiceAvailableLocked()1732     private boolean isAugmentedAutofillServiceAvailableLocked() {
1733         if (mMaster.verbose) {
1734             Slog.v(TAG, "isAugmentedAutofillService(): "
1735                     + "setupCompleted=" + isSetupCompletedLocked()
1736                     + ", disabled=" + isDisabledByUserRestrictionsLocked()
1737                     + ", augmentedService="
1738                     + mMaster.mAugmentedAutofillResolver.getServiceName(mUserId));
1739         }
1740         if (!isSetupCompletedLocked() || isDisabledByUserRestrictionsLocked()
1741                 || mMaster.mAugmentedAutofillResolver.getServiceName(mUserId) == null) {
1742             return false;
1743         }
1744         return true;
1745     }
1746 
isAugmentedAutofillServiceForUserLocked(int callingUid)1747     boolean isAugmentedAutofillServiceForUserLocked(int callingUid) {
1748         return mRemoteAugmentedAutofillServiceInfo != null
1749                 && mRemoteAugmentedAutofillServiceInfo.applicationInfo.uid == callingUid;
1750     }
1751 
1752     /**
1753      * Sets which packages and activities can trigger augmented autofill.
1754      *
1755      * @return whether caller UID is the augmented autofill service for the user
1756      */
1757     @GuardedBy("mLock")
setAugmentedAutofillWhitelistLocked(@ullable List<String> packages, @Nullable List<ComponentName> activities, int callingUid)1758     boolean setAugmentedAutofillWhitelistLocked(@Nullable List<String> packages,
1759             @Nullable List<ComponentName> activities, int callingUid) {
1760 
1761         if (!isCalledByAugmentedAutofillServiceLocked("setAugmentedAutofillWhitelistLocked",
1762                 callingUid)) {
1763             return false;
1764         }
1765         if (mMaster.verbose) {
1766             Slog.v(TAG, "setAugmentedAutofillWhitelistLocked(packages=" + packages + ", activities="
1767                     + activities + ")");
1768         }
1769         allowlistForAugmentedAutofillPackages(packages, activities);
1770         final String serviceName;
1771         if (mRemoteAugmentedAutofillServiceInfo != null) {
1772             serviceName = mRemoteAugmentedAutofillServiceInfo.getComponentName()
1773                     .flattenToShortString();
1774         } else {
1775             Slog.e(TAG, "setAugmentedAutofillWhitelistLocked(): no service");
1776             serviceName = "N/A";
1777         }
1778 
1779         final LogMaker log = new LogMaker(MetricsEvent.AUTOFILL_AUGMENTED_WHITELIST_REQUEST)
1780                 .addTaggedData(MetricsEvent.FIELD_AUTOFILL_SERVICE, serviceName);
1781         if (packages != null) {
1782             log.addTaggedData(MetricsEvent.FIELD_AUTOFILL_NUMBER_PACKAGES, packages.size());
1783         }
1784         if (activities != null) {
1785             log.addTaggedData(MetricsEvent.FIELD_AUTOFILL_NUMBER_ACTIVITIES, activities.size());
1786         }
1787         mMetricsLogger.write(log);
1788 
1789         return true;
1790     }
1791 
1792     @GuardedBy("mLock")
isCalledByAugmentedAutofillServiceLocked(@onNull String methodName, int callingUid)1793     private boolean isCalledByAugmentedAutofillServiceLocked(@NonNull String methodName,
1794             int callingUid) {
1795         // Lazy load service first
1796         final RemoteAugmentedAutofillService service = getRemoteAugmentedAutofillServiceLocked();
1797         if (service == null) {
1798             Slog.w(TAG, methodName + "() called by UID " + callingUid
1799                     + ", but there is no augmented autofill service defined for user "
1800                     + getUserId());
1801             return false;
1802         }
1803 
1804         if (getAugmentedAutofillServiceUidLocked() != callingUid) {
1805             Slog.w(TAG, methodName + "() called by UID " + callingUid
1806                     + ", but service UID is " + getAugmentedAutofillServiceUidLocked()
1807                     + " for user " + getUserId());
1808             return false;
1809         }
1810         return true;
1811     }
1812 
1813     @Nullable
getCredentialAutofillService(Context context)1814     private ComponentName getCredentialAutofillService(Context context) {
1815         ComponentName componentName = null;
1816         String credentialManagerAutofillCompName = context.getResources().getString(
1817                 R.string.config_defaultCredentialManagerAutofillService);
1818         if (credentialManagerAutofillCompName != null
1819                 && !credentialManagerAutofillCompName.isEmpty()) {
1820             componentName = ComponentName.unflattenFromString(
1821                     credentialManagerAutofillCompName);
1822         }
1823         if (componentName == null) {
1824             Slog.w(TAG, "Invalid CredentialAutofillService");
1825         }
1826         return componentName;
1827     }
1828 
1829     @GuardedBy("mLock")
getAugmentedAutofillServiceUidLocked()1830     private int getAugmentedAutofillServiceUidLocked() {
1831         if (mRemoteAugmentedAutofillServiceInfo == null) {
1832             if (mMaster.verbose) {
1833                 Slog.v(TAG, "getAugmentedAutofillServiceUid(): "
1834                         + "no mRemoteAugmentedAutofillServiceInfo");
1835             }
1836             return Process.INVALID_UID;
1837         }
1838         return mRemoteAugmentedAutofillServiceInfo.applicationInfo.uid;
1839     }
1840 
1841     @GuardedBy("mLock")
isWhitelistedForAugmentedAutofillLocked(@onNull ComponentName componentName)1842     boolean isWhitelistedForAugmentedAutofillLocked(@NonNull ComponentName componentName) {
1843         return mMaster.mAugmentedAutofillState.isWhitelisted(mUserId, componentName);
1844     }
1845 
1846     /**
1847      * @throws IllegalArgumentException if packages or components are empty.
1848      */
allowlistForAugmentedAutofillPackages(@ullable List<String> packages, @Nullable List<ComponentName> components)1849     private void allowlistForAugmentedAutofillPackages(@Nullable List<String> packages,
1850             @Nullable List<ComponentName> components) {
1851         // TODO(b/123100824): add CTS test for when it's null
1852         synchronized (mLock) {
1853             if (mMaster.verbose) {
1854                 Slog.v(TAG, "whitelisting packages: " + packages + "and activities: " + components);
1855             }
1856             mMaster.mAugmentedAutofillState.setWhitelist(mUserId, packages, components);
1857         }
1858     }
1859 
1860     /**
1861      * Resets the augmented autofill allowlist.
1862      */
1863     @GuardedBy("mLock")
resetAugmentedAutofillWhitelistLocked()1864     void resetAugmentedAutofillWhitelistLocked() {
1865         if (mMaster.verbose) {
1866             Slog.v(TAG, "resetting augmented autofill whitelist");
1867         }
1868         mMaster.mAugmentedAutofillState.resetWhitelist(mUserId);
1869     }
1870 
sendStateToClients(boolean resetClient)1871     private void sendStateToClients(boolean resetClient) {
1872         final RemoteCallbackList<IAutoFillManagerClient> clients;
1873         final int userClientCount;
1874         synchronized (mLock) {
1875             if (mClients == null) {
1876                 return;
1877             }
1878             clients = mClients;
1879             userClientCount = clients.beginBroadcast();
1880         }
1881         try {
1882             for (int i = 0; i < userClientCount; i++) {
1883                 final IAutoFillManagerClient client = clients.getBroadcastItem(i);
1884                 try {
1885                     final boolean resetSession;
1886                     final boolean isEnabled;
1887                     synchronized (mLock) {
1888                         resetSession = resetClient || isClientSessionDestroyedLocked(client);
1889                         isEnabled = isEnabledLocked();
1890                     }
1891                     int flags = 0;
1892                     if (isEnabled) {
1893                         flags |= AutofillManager.SET_STATE_FLAG_ENABLED;
1894                     }
1895                     if (resetSession) {
1896                         flags |= AutofillManager.SET_STATE_FLAG_RESET_SESSION;
1897                     }
1898                     if (resetClient) {
1899                         flags |= AutofillManager.SET_STATE_FLAG_RESET_CLIENT;
1900                     }
1901                     if (sDebug) {
1902                         flags |= AutofillManager.SET_STATE_FLAG_DEBUG;
1903                     }
1904                     if (sVerbose) {
1905                         flags |= AutofillManager.SET_STATE_FLAG_VERBOSE;
1906                     }
1907                     client.setState(flags);
1908                 } catch (RemoteException re) {
1909                     /* ignore */
1910                 }
1911             }
1912         } finally {
1913             clients.finishBroadcast();
1914         }
1915     }
1916 
1917     @GuardedBy("mLock")
isClientSessionDestroyedLocked(IAutoFillManagerClient client)1918     private boolean isClientSessionDestroyedLocked(IAutoFillManagerClient client) {
1919         final int sessionCount = mSessions.size();
1920         for (int i = 0; i < sessionCount; i++) {
1921             final Session session = mSessions.valueAt(i);
1922             if (session.getClient().equals(client)) {
1923                 return session.isDestroyed();
1924             }
1925         }
1926         return true;
1927     }
1928 
1929     /**
1930      * Called by {@link Session} when service asked to disable autofill for an app.
1931      */
disableAutofillForApp(@onNull String packageName, long duration, int sessionId, boolean compatMode)1932     void disableAutofillForApp(@NonNull String packageName, long duration, int sessionId,
1933             boolean compatMode) {
1934         synchronized (mLock) {
1935             long expiration = SystemClock.elapsedRealtime() + duration;
1936             // Protect it against overflow
1937             if (expiration < 0) {
1938                 expiration = Long.MAX_VALUE;
1939             }
1940             mDisabledInfoCache.addDisabledAppLocked(mUserId, packageName, expiration);
1941 
1942             int intDuration = duration > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) duration;
1943             mMetricsLogger.write(Helper.newLogMaker(MetricsEvent.AUTOFILL_SERVICE_DISABLED_APP,
1944                     packageName, getServicePackageName(), sessionId, compatMode)
1945                     .addTaggedData(MetricsEvent.FIELD_AUTOFILL_DURATION, intDuration));
1946         }
1947     }
1948 
1949     /**
1950      * Called by {@link Session} when service asked to disable autofill an app.
1951      */
disableAutofillForActivity(@onNull ComponentName componentName, long duration, int sessionId, boolean compatMode)1952     void disableAutofillForActivity(@NonNull ComponentName componentName, long duration,
1953             int sessionId, boolean compatMode) {
1954         synchronized (mLock) {
1955             long expiration = SystemClock.elapsedRealtime() + duration;
1956             // Protect it against overflow
1957             if (expiration < 0) {
1958                 expiration = Long.MAX_VALUE;
1959             }
1960             mDisabledInfoCache.addDisabledActivityLocked(mUserId, componentName, expiration);
1961             final int intDuration = duration > Integer.MAX_VALUE
1962                     ? Integer.MAX_VALUE
1963                     : (int) duration;
1964 
1965             final LogMaker log = Helper.newLogMaker(MetricsEvent.AUTOFILL_SERVICE_DISABLED_ACTIVITY,
1966                     componentName, getServicePackageName(), sessionId, compatMode)
1967                     .addTaggedData(MetricsEvent.FIELD_AUTOFILL_DURATION, intDuration);
1968             mMetricsLogger.write(log);
1969         }
1970     }
1971 
1972     /**
1973      * Checks if autofill is disabled by service to the given activity.
1974      */
1975     @GuardedBy("mLock")
isAutofillDisabledLocked(@onNull ComponentName componentName)1976     private boolean isAutofillDisabledLocked(@NonNull ComponentName componentName) {
1977         return mDisabledInfoCache.isAutofillDisabledLocked(mUserId, componentName);
1978     }
1979 
1980     // Called by AutofillManager, checks UID.
isFieldClassificationEnabled(int callingUid)1981     boolean isFieldClassificationEnabled(int callingUid) {
1982         synchronized (mLock) {
1983             if (!isCalledByServiceLocked("isFieldClassificationEnabled", callingUid)) {
1984                 return false;
1985             }
1986             return isFieldClassificationEnabledLocked();
1987         }
1988     }
1989 
1990     // Called by internally, no need to check UID.
isFieldClassificationEnabledLocked()1991     boolean isFieldClassificationEnabledLocked() {
1992         return Settings.Secure.getIntForUser(
1993                 getContext().getContentResolver(),
1994                 Settings.Secure.AUTOFILL_FEATURE_FIELD_CLASSIFICATION, 1,
1995                 mUserId) == 1;
1996     }
1997 
getFieldClassificationStrategy()1998     FieldClassificationStrategy getFieldClassificationStrategy() {
1999         return mFieldClassificationStrategy;
2000     }
2001 
getAvailableFieldClassificationAlgorithms(int callingUid)2002     String[] getAvailableFieldClassificationAlgorithms(int callingUid) {
2003         synchronized (mLock) {
2004             if (!isCalledByServiceLocked("getFCAlgorithms()", callingUid)) {
2005                 return null;
2006             }
2007         }
2008         return mFieldClassificationStrategy.getAvailableAlgorithms();
2009     }
2010 
getDefaultFieldClassificationAlgorithm(int callingUid)2011     String getDefaultFieldClassificationAlgorithm(int callingUid) {
2012         synchronized (mLock) {
2013             if (!isCalledByServiceLocked("getDefaultFCAlgorithm()", callingUid)) {
2014                 return null;
2015             }
2016         }
2017         return mFieldClassificationStrategy.getDefaultAlgorithm();
2018     }
2019 
getRemoteInlineSuggestionRenderServiceLocked()2020     @Nullable RemoteInlineSuggestionRenderService getRemoteInlineSuggestionRenderServiceLocked() {
2021         if (mRemoteInlineSuggestionRenderService == null) {
2022             final ComponentName componentName = RemoteInlineSuggestionRenderService
2023                 .getServiceComponentName(getContext(), mUserId);
2024             if (componentName == null) {
2025                 Slog.w(TAG, "No valid component found for InlineSuggestionRenderService");
2026                 return null;
2027             }
2028 
2029             mRemoteInlineSuggestionRenderService = new RemoteInlineSuggestionRenderService(
2030                     getContext(), componentName, InlineSuggestionRenderService.SERVICE_INTERFACE,
2031                     mUserId, new InlineSuggestionRenderCallbacksImpl(),
2032                     mMaster.isBindInstantServiceAllowed(), mMaster.verbose);
2033         }
2034 
2035         return mRemoteInlineSuggestionRenderService;
2036     }
2037 
2038     private class InlineSuggestionRenderCallbacksImpl implements
2039             RemoteInlineSuggestionRenderService.InlineSuggestionRenderCallbacks {
2040 
2041         @Override // from InlineSuggestionRenderCallbacksImpl
onServiceDied(@onNull RemoteInlineSuggestionRenderService service)2042         public void onServiceDied(@NonNull RemoteInlineSuggestionRenderService service) {
2043             Slog.w(TAG, "remote service died: " + service);
2044             synchronized (mLock) {
2045                 resetExtServiceLocked();
2046             }
2047         }
2048     }
2049 
onSwitchInputMethod()2050     void onSwitchInputMethod() {
2051         synchronized (mLock) {
2052             final int sessionCount = mSessions.size();
2053             for (int i = 0; i < sessionCount; i++) {
2054                 final Session session = mSessions.valueAt(i);
2055                 session.onSwitchInputMethodLocked();
2056             }
2057         }
2058     }
2059 
2060     @GuardedBy("mLock")
getRemoteFieldClassificationServiceLocked()2061     @Nullable RemoteFieldClassificationService getRemoteFieldClassificationServiceLocked() {
2062         if (mRemoteFieldClassificationService == null) {
2063             final String serviceName = mMaster.mFieldClassificationResolver.getServiceName(mUserId);
2064             if (serviceName == null) {
2065                 if (mMaster.verbose) {
2066                     Slog.v(TAG, "getRemoteFieldClassificationServiceLocked(): not set");
2067                 }
2068                 return null;
2069             }
2070             if (sVerbose) {
2071                 Slog.v(TAG, "getRemoteFieldClassificationServiceLocked serviceName: "
2072                         + serviceName);
2073             }
2074             boolean sTemporaryFieldDetectionService =
2075                     mMaster.mFieldClassificationResolver.isTemporary(mUserId);
2076             final Pair<ServiceInfo, ComponentName> pair = RemoteFieldClassificationService
2077                     .getComponentName(serviceName, mUserId, sTemporaryFieldDetectionService);
2078             if (pair == null) {
2079                 Slog.w(TAG, "RemoteFieldClassificationService.getComponentName returned null "
2080                         + "with serviceName: " + serviceName);
2081                 return null;
2082             }
2083 
2084             mRemoteFieldClassificationServiceInfo = pair.first;
2085             final ComponentName componentName = pair.second;
2086             if (sVerbose) {
2087                 Slog.v(TAG, "getRemoteFieldClassificationServiceLocked(): " + componentName);
2088             }
2089             final int serviceUid = mRemoteFieldClassificationServiceInfo.applicationInfo.uid;
2090             mRemoteFieldClassificationService = new RemoteFieldClassificationService(getContext(),
2091                     componentName, serviceUid, mUserId);
2092         }
2093 
2094         return mRemoteFieldClassificationService;
2095     }
2096 
2097     @GuardedBy("mLock")
2098     @Nullable RemoteFieldClassificationService
getRemoteFieldClassificationServiceIfCreatedLocked()2099             getRemoteFieldClassificationServiceIfCreatedLocked() {
2100         return mRemoteFieldClassificationService;
2101     }
2102 
2103 
isPccClassificationEnabled()2104     public boolean isPccClassificationEnabled() {
2105         boolean result = isPccClassificationEnabledInternal();
2106         if (sVerbose) {
2107             Slog.v(TAG, "pccEnabled: " + result);
2108         }
2109         return result;
2110     }
2111 
isPccClassificationEnabledInternal()2112     public boolean isPccClassificationEnabledInternal() {
2113         boolean flagEnabled = mMaster.isPccClassificationFlagEnabled();
2114         if (!flagEnabled) return false;
2115         synchronized (mLock) {
2116             return getRemoteFieldClassificationServiceLocked() != null;
2117         }
2118     }
2119 
isAutofillCredmanIntegrationEnabled()2120     public boolean isAutofillCredmanIntegrationEnabled() {
2121         return mMaster.isAutofillCredmanIntegrationEnabled();
2122     }
2123 
2124     /**
2125      * Called when the {@link AutofillManagerService#mFieldClassificationResolver}
2126      * changed (among other places).
2127      */
updateRemoteFieldClassificationService()2128     void updateRemoteFieldClassificationService() {
2129         synchronized (mLock) {
2130             if (mRemoteFieldClassificationService != null) {
2131                 if (sVerbose) {
2132                     Slog.v(TAG, "updateRemoteFieldClassificationService(): "
2133                             + "destroying old remote service");
2134                 }
2135                 mRemoteFieldClassificationService.unbind();
2136                 mRemoteFieldClassificationService = null;
2137                 mRemoteFieldClassificationServiceInfo = null;
2138             }
2139 
2140             final boolean available = isFieldClassificationServiceAvailableLocked();
2141             if (sVerbose) Slog.v(TAG, "updateRemoteFieldClassificationService(): " + available);
2142 
2143             if (available) {
2144                 mRemoteFieldClassificationService = getRemoteFieldClassificationServiceLocked();
2145             }
2146         }
2147     }
2148 
isFieldClassificationServiceAvailableLocked()2149     private boolean isFieldClassificationServiceAvailableLocked() {
2150         if (mMaster.verbose) {
2151             Slog.v(TAG, "isFieldClassificationService(): "
2152                     + "setupCompleted=" + isSetupCompletedLocked()
2153                     + ", disabled=" + isDisabledByUserRestrictionsLocked()
2154                     + ", augmentedService="
2155                     + mMaster.mFieldClassificationResolver.getServiceName(mUserId));
2156         }
2157         if (!isSetupCompletedLocked() || isDisabledByUserRestrictionsLocked()
2158                 || mMaster.mFieldClassificationResolver.getServiceName(mUserId) == null) {
2159             return false;
2160         }
2161         return true;
2162     }
2163 
isRemoteClassificationServiceForUserLocked(int callingUid)2164     boolean isRemoteClassificationServiceForUserLocked(int callingUid) {
2165         return mRemoteFieldClassificationServiceInfo != null
2166                 && mRemoteFieldClassificationServiceInfo.applicationInfo.uid == callingUid;
2167     }
2168 
2169     @Override
toString()2170     public String toString() {
2171         return "AutofillManagerServiceImpl: [userId=" + mUserId
2172                 + ", component=" + (mInfo != null
2173                 ? mInfo.getServiceInfo().getComponentName() : null) + "]";
2174     }
2175 
2176     /** Task used to prune abandoned session */
2177     private class PruneTask extends AsyncTask<Void, Void, Void> {
2178         @Override
doInBackground(Void... ignored)2179         protected Void doInBackground(Void... ignored) {
2180             int numSessionsToRemove;
2181 
2182             SparseArray<IBinder> sessionsToRemove;
2183 
2184             synchronized (mLock) {
2185                 numSessionsToRemove = mSessions.size();
2186                 sessionsToRemove = new SparseArray<>(numSessionsToRemove);
2187 
2188                 for (int i = 0; i < numSessionsToRemove; i++) {
2189                     Session session = mSessions.valueAt(i);
2190 
2191                     sessionsToRemove.put(session.id, session.getActivityTokenLocked());
2192                 }
2193             }
2194 
2195             final ActivityTaskManagerInternal atmInternal = LocalServices.getService(
2196                     ActivityTaskManagerInternal.class);
2197 
2198             // Only remove sessions which's activities are not known to the activity manager anymore
2199             for (int i = 0; i < numSessionsToRemove; i++) {
2200                 // The activity task manager cannot resolve activities that have been removed.
2201                 if (atmInternal.getActivityName(sessionsToRemove.valueAt(i)) != null) {
2202                     sessionsToRemove.removeAt(i);
2203                     i--;
2204                     numSessionsToRemove--;
2205                 }
2206             }
2207 
2208             synchronized (mLock) {
2209                 for (int i = 0; i < numSessionsToRemove; i++) {
2210                     Session sessionToRemove = mSessions.get(sessionsToRemove.keyAt(i));
2211 
2212                     if (sessionToRemove != null && sessionsToRemove.valueAt(i)
2213                             == sessionToRemove.getActivityTokenLocked()) {
2214                         if (sessionToRemove.isSaveUiShowingLocked()) {
2215                             if (sVerbose) {
2216                                 Slog.v(TAG, "Session " + sessionToRemove.id + " is saving");
2217                             }
2218                         } else {
2219                             if (sDebug) {
2220                                 Slog.i(TAG, "Prune session " + sessionToRemove.id + " ("
2221                                     + sessionToRemove.getActivityTokenLocked() + ")");
2222                             }
2223                             sessionToRemove.removeFromServiceLocked();
2224                         }
2225                     }
2226                 }
2227             }
2228 
2229             return null;
2230         }
2231     }
2232 }
2233