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.FillRequest.FLAG_MANUAL_REQUEST;
20 import static android.view.autofill.AutofillManager.ACTION_START_SESSION;
21 import static android.view.autofill.AutofillManager.FLAG_ADD_CLIENT_ENABLED;
22 import static android.view.autofill.AutofillManager.FLAG_ADD_CLIENT_ENABLED_FOR_AUGMENTED_AUTOFILL_ONLY;
23 import static android.view.autofill.AutofillManager.NO_SESSION;
24 import static android.view.autofill.AutofillManager.RECEIVER_FLAG_SESSION_FOR_AUGMENTED_AUTOFILL_ONLY;
25 
26 import static com.android.server.autofill.Helper.sDebug;
27 import static com.android.server.autofill.Helper.sVerbose;
28 
29 import android.annotation.NonNull;
30 import android.annotation.Nullable;
31 import android.app.ActivityManagerInternal;
32 import android.content.ComponentName;
33 import android.content.pm.PackageManager;
34 import android.content.pm.PackageManager.NameNotFoundException;
35 import android.content.pm.ServiceInfo;
36 import android.graphics.Rect;
37 import android.metrics.LogMaker;
38 import android.os.AsyncTask;
39 import android.os.Binder;
40 import android.os.Bundle;
41 import android.os.Handler;
42 import android.os.IBinder;
43 import android.os.Looper;
44 import android.os.Process;
45 import android.os.RemoteCallbackList;
46 import android.os.RemoteException;
47 import android.os.SystemClock;
48 import android.os.UserHandle;
49 import android.provider.Settings;
50 import android.service.autofill.AutofillService;
51 import android.service.autofill.AutofillServiceInfo;
52 import android.service.autofill.FieldClassification;
53 import android.service.autofill.FieldClassification.Match;
54 import android.service.autofill.FillEventHistory;
55 import android.service.autofill.FillEventHistory.Event;
56 import android.service.autofill.FillEventHistory.Event.NoSaveReason;
57 import android.service.autofill.FillResponse;
58 import android.service.autofill.IAutoFillService;
59 import android.service.autofill.InlineSuggestionRenderService;
60 import android.service.autofill.SaveInfo;
61 import android.service.autofill.UserData;
62 import android.util.ArrayMap;
63 import android.util.ArraySet;
64 import android.util.DebugUtils;
65 import android.util.LocalLog;
66 import android.util.Pair;
67 import android.util.Slog;
68 import android.util.SparseArray;
69 import android.view.autofill.AutofillId;
70 import android.view.autofill.AutofillManager;
71 import android.view.autofill.AutofillManager.SmartSuggestionMode;
72 import android.view.autofill.AutofillValue;
73 import android.view.autofill.IAutoFillManagerClient;
74 
75 import com.android.internal.R;
76 import com.android.internal.annotations.GuardedBy;
77 import com.android.internal.logging.MetricsLogger;
78 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
79 import com.android.internal.os.IResultReceiver;
80 import com.android.server.LocalServices;
81 import com.android.server.autofill.AutofillManagerService.AutofillCompatState;
82 import com.android.server.autofill.AutofillManagerService.DisabledInfoCache;
83 import com.android.server.autofill.RemoteAugmentedAutofillService.RemoteAugmentedAutofillServiceCallbacks;
84 import com.android.server.autofill.ui.AutoFillUI;
85 import com.android.server.contentcapture.ContentCaptureManagerInternal;
86 import com.android.server.infra.AbstractPerUserSystemService;
87 import com.android.server.inputmethod.InputMethodManagerInternal;
88 import com.android.server.wm.ActivityTaskManagerInternal;
89 
90 import java.io.PrintWriter;
91 import java.util.ArrayList;
92 import java.util.List;
93 import java.util.Random;
94 /**
95  * Bridge between the {@code system_server}'s {@link AutofillManagerService} and the
96  * app's {@link IAutoFillService} implementation.
97  *
98  */
99 final class AutofillManagerServiceImpl
100         extends AbstractPerUserSystemService<AutofillManagerServiceImpl, AutofillManagerService> {
101 
102     private static final String TAG = "AutofillManagerServiceImpl";
103     private static final int MAX_SESSION_ID_CREATE_TRIES = 2048;
104 
105     /** Minimum interval to prune abandoned sessions */
106     private static final int MAX_ABANDONED_SESSION_MILLIS = 30_000;
107 
108     private final AutoFillUI mUi;
109     private final MetricsLogger mMetricsLogger = new MetricsLogger();
110 
111     @GuardedBy("mLock")
112     private RemoteCallbackList<IAutoFillManagerClient> mClients;
113 
114     @GuardedBy("mLock")
115     private AutofillServiceInfo mInfo;
116 
117     private static final Random sRandom = new Random();
118 
119     private final LocalLog mUiLatencyHistory;
120     private final LocalLog mWtfHistory;
121     private final FieldClassificationStrategy mFieldClassificationStrategy;
122 
123     @GuardedBy("mLock")
124     @Nullable
125     private RemoteInlineSuggestionRenderService mRemoteInlineSuggestionRenderService;
126 
127     /**
128      * Data used for field classification.
129      */
130     @GuardedBy("mLock")
131     private UserData mUserData;
132 
133     private final Handler mHandler = new Handler(Looper.getMainLooper(), null, true);
134 
135     /**
136      * Cache of pending {@link Session}s, keyed by sessionId.
137      *
138      * <p>They're kept until the {@link AutofillService} finished handling a request, an error
139      * occurs, or the session is abandoned.
140      */
141     @GuardedBy("mLock")
142     private final SparseArray<Session> mSessions = new SparseArray<>();
143 
144     /** The last selection */
145     @GuardedBy("mLock")
146     private FillEventHistory mEventHistory;
147 
148     /**
149      * The last inline augmented autofill selection. Note that we don't log the selection from the
150      * dropdown UI since the service owns the UI in that case.
151      */
152     @GuardedBy("mLock")
153     private FillEventHistory mAugmentedAutofillEventHistory;
154 
155     /** Shared instance, doesn't need to be logged */
156     private final AutofillCompatState mAutofillCompatState;
157 
158     /** When was {@link PruneTask} last executed? */
159     private long mLastPrune = 0;
160 
161     /**
162      * Reference to the {@link RemoteAugmentedAutofillService}, is set on demand.
163      */
164     @GuardedBy("mLock")
165     @Nullable
166     private RemoteAugmentedAutofillService mRemoteAugmentedAutofillService;
167 
168     @GuardedBy("mLock")
169     @Nullable
170     private ServiceInfo mRemoteAugmentedAutofillServiceInfo;
171 
172     private final InputMethodManagerInternal mInputMethodManagerInternal;
173 
174     private final ContentCaptureManagerInternal mContentCaptureManagerInternal;
175 
176     private final DisabledInfoCache mDisabledInfoCache;
177 
AutofillManagerServiceImpl(AutofillManagerService master, Object lock, LocalLog uiLatencyHistory, LocalLog wtfHistory, int userId, AutoFillUI ui, AutofillCompatState autofillCompatState, boolean disabled, DisabledInfoCache disableCache)178     AutofillManagerServiceImpl(AutofillManagerService master, Object lock,
179             LocalLog uiLatencyHistory, LocalLog wtfHistory, int userId, AutoFillUI ui,
180             AutofillCompatState autofillCompatState,
181             boolean disabled, DisabledInfoCache disableCache) {
182         super(master, lock, userId);
183 
184         mUiLatencyHistory = uiLatencyHistory;
185         mWtfHistory = wtfHistory;
186         mUi = ui;
187         mFieldClassificationStrategy = new FieldClassificationStrategy(getContext(), userId);
188         mAutofillCompatState = autofillCompatState;
189         mInputMethodManagerInternal = LocalServices.getService(InputMethodManagerInternal.class);
190         mContentCaptureManagerInternal = LocalServices.getService(
191                 ContentCaptureManagerInternal.class);
192         mDisabledInfoCache = disableCache;
193         updateLocked(disabled);
194     }
195 
sendActivityAssistDataToContentCapture(@onNull IBinder activityToken, @NonNull Bundle data)196     boolean sendActivityAssistDataToContentCapture(@NonNull IBinder activityToken,
197             @NonNull Bundle data) {
198         if (mContentCaptureManagerInternal != null) {
199             mContentCaptureManagerInternal.sendActivityAssistData(getUserId(), activityToken, data);
200             return true;
201         }
202 
203         return false;
204     }
205 
206     @GuardedBy("mLock")
onBackKeyPressed()207     void onBackKeyPressed() {
208         final RemoteAugmentedAutofillService remoteService =
209                 getRemoteAugmentedAutofillServiceLocked();
210         if (remoteService != null) {
211             remoteService.onDestroyAutofillWindowsRequest();
212         }
213     }
214 
215     @GuardedBy("mLock")
216     @Override // from PerUserSystemService
updateLocked(boolean disabled)217     protected boolean updateLocked(boolean disabled) {
218         forceRemoveAllSessionsLocked();
219         final boolean enabledChanged = super.updateLocked(disabled);
220         if (enabledChanged) {
221             if (!isEnabledLocked()) {
222                 final int sessionCount = mSessions.size();
223                 for (int i = sessionCount - 1; i >= 0; i--) {
224                     final Session session = mSessions.valueAt(i);
225                     session.removeFromServiceLocked();
226                 }
227             }
228             sendStateToClients(/* resetClient= */ false);
229         }
230         updateRemoteAugmentedAutofillService();
231         updateRemoteInlineSuggestionRenderServiceLocked();
232 
233         return enabledChanged;
234     }
235 
236     @Override // from PerUserSystemService
newServiceInfoLocked(@onNull ComponentName serviceComponent)237     protected ServiceInfo newServiceInfoLocked(@NonNull ComponentName serviceComponent)
238             throws NameNotFoundException {
239         mInfo = new AutofillServiceInfo(getContext(), serviceComponent, mUserId);
240         return mInfo.getServiceInfo();
241     }
242 
243     @Nullable
getUrlBarResourceIdsForCompatMode(@onNull String packageName)244     String[] getUrlBarResourceIdsForCompatMode(@NonNull String packageName) {
245         return mAutofillCompatState.getUrlBarResourceIds(packageName, mUserId);
246     }
247 
248     /**
249      * Adds the client and return the proper flags
250      *
251      * @return {@code 0} if disabled, {@code FLAG_ADD_CLIENT_ENABLED} if enabled (it might be
252      * OR'ed with {@code FLAG_AUGMENTED_AUTOFILL_REQUEST}).
253      */
254     @GuardedBy("mLock")
addClientLocked(IAutoFillManagerClient client, ComponentName componentName)255     int addClientLocked(IAutoFillManagerClient client, ComponentName componentName) {
256         if (mClients == null) {
257             mClients = new RemoteCallbackList<>();
258         }
259         mClients.register(client);
260 
261         if (isEnabledLocked()) return FLAG_ADD_CLIENT_ENABLED;
262 
263         // Check if it's enabled for augmented autofill
264         if (componentName != null && isAugmentedAutofillServiceAvailableLocked()
265                 && isWhitelistedForAugmentedAutofillLocked(componentName)) {
266             return FLAG_ADD_CLIENT_ENABLED_FOR_AUGMENTED_AUTOFILL_ONLY;
267         }
268 
269         // No flags / disabled
270         return 0;
271     }
272 
273     @GuardedBy("mLock")
removeClientLocked(IAutoFillManagerClient client)274     void removeClientLocked(IAutoFillManagerClient client) {
275         if (mClients != null) {
276             mClients.unregister(client);
277         }
278     }
279 
280     @GuardedBy("mLock")
setAuthenticationResultLocked(Bundle data, int sessionId, int authenticationId, int uid)281     void setAuthenticationResultLocked(Bundle data, int sessionId, int authenticationId, int uid) {
282         if (!isEnabledLocked()) {
283             return;
284         }
285         final Session session = mSessions.get(sessionId);
286         if (session != null && uid == session.uid) {
287             session.setAuthenticationResultLocked(data, authenticationId);
288         }
289     }
290 
setHasCallback(int sessionId, int uid, boolean hasIt)291     void setHasCallback(int sessionId, int uid, boolean hasIt) {
292         if (!isEnabledLocked()) {
293             return;
294         }
295         final Session session = mSessions.get(sessionId);
296         if (session != null && uid == session.uid) {
297             synchronized (mLock) {
298                 session.setHasCallbackLocked(hasIt);
299             }
300         }
301     }
302 
303     /**
304      * Starts a new session.
305      *
306      * @return {@code long} whose right-most 32 bits represent the session id (which is always
307      * non-negative), and the left-most contains extra flags (currently either {@code 0} or
308      * {@link AutofillManager#RECEIVER_FLAG_SESSION_FOR_AUGMENTED_AUTOFILL_ONLY}).
309      */
310     @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)311     long startSessionLocked(@NonNull IBinder activityToken, int taskId, int clientUid,
312             @NonNull IBinder clientCallback, @NonNull AutofillId autofillId,
313             @NonNull Rect virtualBounds, @Nullable AutofillValue value, boolean hasCallback,
314             @NonNull ComponentName clientActivity, boolean compatMode,
315             boolean bindInstantServiceAllowed, int flags) {
316         // FLAG_AUGMENTED_AUTOFILL_REQUEST is set in the flags when standard autofill is disabled
317         // but the package is allowlisted for augmented autofill
318         boolean forAugmentedAutofillOnly = (flags
319                 & FLAG_ADD_CLIENT_ENABLED_FOR_AUGMENTED_AUTOFILL_ONLY) != 0;
320         if (!isEnabledLocked() && !forAugmentedAutofillOnly) {
321             return 0;
322         }
323 
324         if (!forAugmentedAutofillOnly && isAutofillDisabledLocked(clientActivity)) {
325             // Standard autofill is enabled, but service disabled autofill for this activity; that
326             // means no session, unless the activity is allowlisted for augmented autofill
327             if (isWhitelistedForAugmentedAutofillLocked(clientActivity)) {
328                 if (sDebug) {
329                     Slog.d(TAG, "startSession(" + clientActivity + "): disabled by service but "
330                             + "whitelisted for augmented autofill");
331                 }
332                 forAugmentedAutofillOnly = true;
333 
334             } else {
335                 if (sDebug) {
336                     Slog.d(TAG, "startSession(" + clientActivity + "): ignored because "
337                             + "disabled by service and not whitelisted for augmented autofill");
338                 }
339                 final IAutoFillManagerClient client = IAutoFillManagerClient.Stub
340                         .asInterface(clientCallback);
341                 try {
342                     client.setSessionFinished(AutofillManager.STATE_DISABLED_BY_SERVICE,
343                             /* autofillableIds= */ null);
344                 } catch (RemoteException e) {
345                     Slog.w(TAG,
346                             "Could not notify " + clientActivity + " that it's disabled: " + e);
347                 }
348 
349                 return NO_SESSION;
350             }
351         }
352 
353         if (sVerbose) {
354             Slog.v(TAG, "startSession(): token=" + activityToken + ", flags=" + flags
355                     + ", forAugmentedAutofillOnly=" + forAugmentedAutofillOnly);
356         }
357 
358         // Occasionally clean up abandoned sessions
359         pruneAbandonedSessionsLocked();
360 
361         final Session newSession = createSessionByTokenLocked(activityToken, taskId, clientUid,
362                 clientCallback, hasCallback, clientActivity, compatMode,
363                 bindInstantServiceAllowed, forAugmentedAutofillOnly, flags);
364         if (newSession == null) {
365             return NO_SESSION;
366         }
367 
368         // Service can be null when it's only for augmented autofill
369         String servicePackageName = mInfo == null ? null : mInfo.getServiceInfo().packageName;
370         final String historyItem =
371                 "id=" + newSession.id + " uid=" + clientUid + " a=" + clientActivity.toShortString()
372                 + " s=" + servicePackageName
373                 + " u=" + mUserId + " i=" + autofillId + " b=" + virtualBounds
374                 + " hc=" + hasCallback + " f=" + flags + " aa=" + forAugmentedAutofillOnly;
375         mMaster.logRequestLocked(historyItem);
376 
377         newSession.updateLocked(autofillId, virtualBounds, value, ACTION_START_SESSION, flags);
378 
379         if (forAugmentedAutofillOnly) {
380             // Must embed the flag in the response, at the high-end side of the long.
381             // (session is always positive, so we don't have to worry about the signal bit)
382             final long extraFlags =
383                     ((long) RECEIVER_FLAG_SESSION_FOR_AUGMENTED_AUTOFILL_ONLY) << 32;
384             final long result = extraFlags | newSession.id;
385             return result;
386         } else {
387             return newSession.id;
388         }
389     }
390 
391     /**
392      * Remove abandoned sessions if needed.
393      */
394     @GuardedBy("mLock")
pruneAbandonedSessionsLocked()395     private void pruneAbandonedSessionsLocked() {
396         long now = System.currentTimeMillis();
397         if (mLastPrune < now - MAX_ABANDONED_SESSION_MILLIS) {
398             mLastPrune = now;
399 
400             if (mSessions.size() > 0) {
401                 (new PruneTask()).execute();
402             }
403         }
404     }
405 
406     @GuardedBy("mLock")
setAutofillFailureLocked(int sessionId, int uid, @NonNull List<AutofillId> ids)407     void setAutofillFailureLocked(int sessionId, int uid, @NonNull List<AutofillId> ids) {
408         if (!isEnabledLocked()) {
409             return;
410         }
411         final Session session = mSessions.get(sessionId);
412         if (session == null || uid != session.uid) {
413             Slog.v(TAG, "setAutofillFailure(): no session for " + sessionId + "(" + uid + ")");
414             return;
415         }
416         session.setAutofillFailureLocked(ids);
417     }
418 
419     @GuardedBy("mLock")
finishSessionLocked(int sessionId, int uid)420     void finishSessionLocked(int sessionId, int uid) {
421         if (!isEnabledLocked()) {
422             return;
423         }
424 
425         final Session session = mSessions.get(sessionId);
426         if (session == null || uid != session.uid) {
427             if (sVerbose) {
428                 Slog.v(TAG, "finishSessionLocked(): no session for " + sessionId + "(" + uid + ")");
429             }
430             return;
431         }
432 
433         final Session.SaveResult saveResult = session.showSaveLocked();
434 
435         session.logContextCommitted(saveResult.getNoSaveUiReason());
436 
437         if (saveResult.isLogSaveShown()) {
438             session.logSaveUiShown();
439         }
440 
441         final boolean finished = saveResult.isRemoveSession();
442         if (sVerbose) Slog.v(TAG, "finishSessionLocked(): session finished on save? " + finished);
443 
444         if (finished) {
445             session.removeFromServiceLocked();
446         }
447     }
448 
449     @GuardedBy("mLock")
cancelSessionLocked(int sessionId, int uid)450     void cancelSessionLocked(int sessionId, int uid) {
451         if (!isEnabledLocked()) {
452             return;
453         }
454 
455         final Session session = mSessions.get(sessionId);
456         if (session == null || uid != session.uid) {
457             Slog.w(TAG, "cancelSessionLocked(): no session for " + sessionId + "(" + uid + ")");
458             return;
459         }
460         session.removeFromServiceLocked();
461     }
462 
463     @GuardedBy("mLock")
disableOwnedAutofillServicesLocked(int uid)464     void disableOwnedAutofillServicesLocked(int uid) {
465         Slog.i(TAG, "disableOwnedServices(" + uid + "): " + mInfo);
466         if (mInfo == null) return;
467 
468         final ServiceInfo serviceInfo = mInfo.getServiceInfo();
469         if (serviceInfo.applicationInfo.uid != uid) {
470             Slog.w(TAG, "disableOwnedServices(): ignored when called by UID " + uid
471                     + " instead of " + serviceInfo.applicationInfo.uid
472                     + " for service " + mInfo);
473             return;
474         }
475 
476 
477         final long identity = Binder.clearCallingIdentity();
478         try {
479             final String autoFillService = getComponentNameLocked();
480             final ComponentName componentName = serviceInfo.getComponentName();
481             if (componentName.equals(ComponentName.unflattenFromString(autoFillService))) {
482                 mMetricsLogger.action(MetricsEvent.AUTOFILL_SERVICE_DISABLED_SELF,
483                         componentName.getPackageName());
484                 Settings.Secure.putStringForUser(getContext().getContentResolver(),
485                         Settings.Secure.AUTOFILL_SERVICE, null, mUserId);
486                 forceRemoveAllSessionsLocked();
487             } else {
488                 Slog.w(TAG, "disableOwnedServices(): ignored because current service ("
489                         + serviceInfo + ") does not match Settings (" + autoFillService + ")");
490             }
491         } finally {
492             Binder.restoreCallingIdentity(identity);
493         }
494     }
495 
496     @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)497     private Session createSessionByTokenLocked(@NonNull IBinder clientActivityToken, int taskId,
498             int clientUid, @NonNull IBinder clientCallback, boolean hasCallback,
499             @NonNull ComponentName clientActivity, boolean compatMode,
500             boolean bindInstantServiceAllowed, boolean forAugmentedAutofillOnly, int flags) {
501         // use random ids so that one app cannot know that another app creates sessions
502         int sessionId;
503         int tries = 0;
504         do {
505             tries++;
506             if (tries > MAX_SESSION_ID_CREATE_TRIES) {
507                 Slog.w(TAG, "Cannot create session in " + MAX_SESSION_ID_CREATE_TRIES + " tries");
508                 return null;
509             }
510 
511             sessionId = Math.abs(sRandom.nextInt());
512         } while (sessionId == 0 || sessionId == NO_SESSION
513                 || mSessions.indexOfKey(sessionId) >= 0);
514 
515         assertCallerLocked(clientActivity, compatMode);
516 
517         // It's null when the session is just for augmented autofill
518         final ComponentName serviceComponentName = mInfo == null ? null
519                 : mInfo.getServiceInfo().getComponentName();
520         final Session newSession = new Session(this, mUi, getContext(), mHandler, mUserId, mLock,
521                 sessionId, taskId, clientUid, clientActivityToken, clientCallback, hasCallback,
522                 mUiLatencyHistory, mWtfHistory, serviceComponentName,
523                 clientActivity, compatMode, bindInstantServiceAllowed, forAugmentedAutofillOnly,
524                 flags, mInputMethodManagerInternal);
525         mSessions.put(newSession.id, newSession);
526 
527         return newSession;
528     }
529 
530     /**
531      * Asserts the component is owned by the caller.
532      */
assertCallerLocked(@onNull ComponentName componentName, boolean compatMode)533     private void assertCallerLocked(@NonNull ComponentName componentName, boolean compatMode) {
534         final String packageName = componentName.getPackageName();
535         final PackageManager pm = getContext().getPackageManager();
536         final int callingUid = Binder.getCallingUid();
537         final int packageUid;
538         try {
539             packageUid = pm.getPackageUidAsUser(packageName, UserHandle.getCallingUserId());
540         } catch (NameNotFoundException e) {
541             throw new SecurityException("Could not verify UID for " + componentName);
542         }
543         if (callingUid != packageUid && !LocalServices.getService(ActivityManagerInternal.class)
544                 .hasRunningActivity(callingUid, packageName)) {
545             final String[] packages = pm.getPackagesForUid(callingUid);
546             final String callingPackage = packages != null ? packages[0] : "uid-" + callingUid;
547             Slog.w(TAG, "App (package=" + callingPackage + ", UID=" + callingUid
548                     + ") passed component (" + componentName + ") owned by UID " + packageUid);
549 
550             // NOTE: not using Helper.newLogMaker() because we don't have the session id
551             final LogMaker log = new LogMaker(MetricsEvent.AUTOFILL_FORGED_COMPONENT_ATTEMPT)
552                     .setPackageName(callingPackage)
553                     .addTaggedData(MetricsEvent.FIELD_AUTOFILL_SERVICE, getServicePackageName())
554                     .addTaggedData(MetricsEvent.FIELD_AUTOFILL_FORGED_COMPONENT_NAME,
555                             componentName == null ? "null" : componentName.flattenToShortString());
556             if (compatMode) {
557                 log.addTaggedData(MetricsEvent.FIELD_AUTOFILL_COMPAT_MODE, 1);
558             }
559             mMetricsLogger.write(log);
560 
561             throw new SecurityException("Invalid component: " + componentName);
562         }
563     }
564 
565     /**
566      * Restores a session after an activity was temporarily destroyed.
567      *
568      * @param sessionId The id of the session to restore
569      * @param uid UID of the process that tries to restore the session
570      * @param activityToken The new instance of the activity
571      * @param appCallback The callbacks to the activity
572      */
restoreSession(int sessionId, int uid, @NonNull IBinder activityToken, @NonNull IBinder appCallback)573     boolean restoreSession(int sessionId, int uid, @NonNull IBinder activityToken,
574             @NonNull IBinder appCallback) {
575         final Session session = mSessions.get(sessionId);
576 
577         if (session == null || uid != session.uid) {
578             return false;
579         } else {
580             session.switchActivity(activityToken, appCallback);
581             return true;
582         }
583     }
584 
585     /**
586      * Updates a session and returns whether it should be restarted.
587      */
588     @GuardedBy("mLock")
updateSessionLocked(int sessionId, int uid, AutofillId autofillId, Rect virtualBounds, AutofillValue value, int action, int flags)589     boolean updateSessionLocked(int sessionId, int uid, AutofillId autofillId, Rect virtualBounds,
590             AutofillValue value, int action, int flags) {
591         final Session session = mSessions.get(sessionId);
592         if (session == null || session.uid != uid) {
593             if ((flags & FLAG_MANUAL_REQUEST) != 0) {
594                 if (sDebug) {
595                     Slog.d(TAG, "restarting session " + sessionId + " due to manual request on "
596                             + autofillId);
597                 }
598                 return true;
599             }
600             if (sVerbose) {
601                 Slog.v(TAG, "updateSessionLocked(): session gone for " + sessionId
602                         + "(" + uid + ")");
603             }
604             return false;
605         }
606 
607         session.updateLocked(autofillId, virtualBounds, value, action, flags);
608         return false;
609     }
610 
611     @GuardedBy("mLock")
removeSessionLocked(int sessionId)612     void removeSessionLocked(int sessionId) {
613         mSessions.remove(sessionId);
614     }
615 
616     /**
617      * Ges the previous sessions asked to be kept alive in a given activity task.
618      *
619      * @param session session calling this method (so it's excluded from the result).
620      */
621     @Nullable
622     @GuardedBy("mLock")
getPreviousSessionsLocked(@onNull Session session)623     ArrayList<Session> getPreviousSessionsLocked(@NonNull Session session) {
624         final int size = mSessions.size();
625         ArrayList<Session> previousSessions = null;
626         for (int i = 0; i < size; i++) {
627             final Session previousSession = mSessions.valueAt(i);
628             if (previousSession.taskId == session.taskId && previousSession.id != session.id
629                     && (previousSession.getSaveInfoFlagsLocked() & SaveInfo.FLAG_DELAY_SAVE) != 0) {
630                 if (previousSessions == null) {
631                     previousSessions = new ArrayList<>(size);
632                 }
633                 previousSessions.add(previousSession);
634             }
635         }
636         // TODO(b/113281366): remove returned sessions / add CTS test
637         return previousSessions;
638     }
639 
handleSessionSave(Session session)640     void handleSessionSave(Session session) {
641         synchronized (mLock) {
642             if (mSessions.get(session.id) == null) {
643                 Slog.w(TAG, "handleSessionSave(): already gone: " + session.id);
644 
645                 return;
646             }
647             session.callSaveLocked();
648         }
649     }
650 
onPendingSaveUi(int operation, @NonNull IBinder token)651     void onPendingSaveUi(int operation, @NonNull IBinder token) {
652         if (sVerbose) Slog.v(TAG, "onPendingSaveUi(" + operation + "): " + token);
653         synchronized (mLock) {
654             final int sessionCount = mSessions.size();
655             for (int i = sessionCount - 1; i >= 0; i--) {
656                 final Session session = mSessions.valueAt(i);
657                 if (session.isSaveUiPendingForTokenLocked(token)) {
658                     session.onPendingSaveUi(operation, token);
659                     return;
660                 }
661             }
662         }
663         if (sDebug) {
664             Slog.d(TAG, "No pending Save UI for token " + token + " and operation "
665                     + DebugUtils.flagsToString(AutofillManager.class, "PENDING_UI_OPERATION_",
666                             operation));
667         }
668     }
669 
670     @GuardedBy("mLock")
671     @Override // from PerUserSystemService
handlePackageUpdateLocked(@onNull String packageName)672     protected void handlePackageUpdateLocked(@NonNull String packageName) {
673         final ServiceInfo serviceInfo = mFieldClassificationStrategy.getServiceInfo();
674         if (serviceInfo != null && serviceInfo.packageName.equals(packageName)) {
675             resetExtServiceLocked();
676         }
677     }
678 
679     @GuardedBy("mLock")
resetExtServiceLocked()680     void resetExtServiceLocked() {
681         if (sVerbose) Slog.v(TAG, "reset autofill service.");
682         mFieldClassificationStrategy.reset();
683     }
684 
685     @GuardedBy("mLock")
destroyLocked()686     void destroyLocked() {
687         if (sVerbose) Slog.v(TAG, "destroyLocked()");
688 
689         resetExtServiceLocked();
690 
691         final int numSessions = mSessions.size();
692         final ArraySet<RemoteFillService> remoteFillServices = new ArraySet<>(numSessions);
693         for (int i = 0; i < numSessions; i++) {
694             final RemoteFillService remoteFillService = mSessions.valueAt(i).destroyLocked();
695             if (remoteFillService != null) {
696                 remoteFillServices.add(remoteFillService);
697             }
698         }
699         mSessions.clear();
700         for (int i = 0; i < remoteFillServices.size(); i++) {
701             remoteFillServices.valueAt(i).destroy();
702         }
703 
704         sendStateToClients(/* resetclient=*/ true);
705         if (mClients != null) {
706             mClients.kill();
707             mClients = null;
708         }
709     }
710 
711     /**
712      * Initializes the last fill selection after an autofill service returned a new
713      * {@link FillResponse}.
714      */
setLastResponse(int sessionId, @NonNull FillResponse response)715     void setLastResponse(int sessionId, @NonNull FillResponse response) {
716         synchronized (mLock) {
717             mEventHistory = new FillEventHistory(sessionId, response.getClientState());
718         }
719     }
720 
setLastAugmentedAutofillResponse(int sessionId)721     void setLastAugmentedAutofillResponse(int sessionId) {
722         synchronized (mLock) {
723             mAugmentedAutofillEventHistory = new FillEventHistory(sessionId, /* clientState= */
724                     null);
725         }
726     }
727 
728     /**
729      * Resets the last fill selection.
730      */
resetLastResponse()731     void resetLastResponse() {
732         synchronized (mLock) {
733             mEventHistory = null;
734         }
735     }
736 
resetLastAugmentedAutofillResponse()737     void resetLastAugmentedAutofillResponse() {
738         synchronized (mLock) {
739             mAugmentedAutofillEventHistory = null;
740         }
741     }
742 
743     @GuardedBy("mLock")
isValidEventLocked(String method, int sessionId)744     private boolean isValidEventLocked(String method, int sessionId) {
745         if (mEventHistory == null) {
746             Slog.w(TAG, method + ": not logging event because history is null");
747             return false;
748         }
749         if (sessionId != mEventHistory.getSessionId()) {
750             if (sDebug) {
751                 Slog.d(TAG, method + ": not logging event for session " + sessionId
752                         + " because tracked session is " + mEventHistory.getSessionId());
753             }
754             return false;
755         }
756         return true;
757     }
758 
759     /**
760      * Updates the last fill selection when an authentication was selected.
761      */
setAuthenticationSelected(int sessionId, @Nullable Bundle clientState)762     void setAuthenticationSelected(int sessionId, @Nullable Bundle clientState) {
763         synchronized (mLock) {
764             if (isValidEventLocked("setAuthenticationSelected()", sessionId)) {
765                 mEventHistory.addEvent(
766                         new Event(Event.TYPE_AUTHENTICATION_SELECTED, null, clientState, null, null,
767                                 null, null, null, null, null, null));
768             }
769         }
770     }
771 
772     /**
773      * Updates the last fill selection when an dataset authentication was selected.
774      */
logDatasetAuthenticationSelected(@ullable String selectedDataset, int sessionId, @Nullable Bundle clientState)775     void logDatasetAuthenticationSelected(@Nullable String selectedDataset, int sessionId,
776             @Nullable Bundle clientState) {
777         synchronized (mLock) {
778             if (isValidEventLocked("logDatasetAuthenticationSelected()", sessionId)) {
779                 mEventHistory.addEvent(
780                         new Event(Event.TYPE_DATASET_AUTHENTICATION_SELECTED, selectedDataset,
781                                 clientState, null, null, null, null, null, null, null, null));
782             }
783         }
784     }
785 
786     /**
787      * Updates the last fill selection when an save Ui is shown.
788      */
logSaveShown(int sessionId, @Nullable Bundle clientState)789     void logSaveShown(int sessionId, @Nullable Bundle clientState) {
790         synchronized (mLock) {
791             if (isValidEventLocked("logSaveShown()", sessionId)) {
792                 mEventHistory.addEvent(new Event(Event.TYPE_SAVE_SHOWN, null, clientState, null,
793                         null, null, null, null, null, null, null));
794             }
795         }
796     }
797 
798     /**
799      * Updates the last fill response when a dataset was selected.
800      */
logDatasetSelected(@ullable String selectedDataset, int sessionId, @Nullable Bundle clientState)801     void logDatasetSelected(@Nullable String selectedDataset, int sessionId,
802             @Nullable Bundle clientState) {
803         synchronized (mLock) {
804             if (isValidEventLocked("logDatasetSelected()", sessionId)) {
805                 mEventHistory.addEvent(
806                         new Event(Event.TYPE_DATASET_SELECTED, selectedDataset, clientState, null,
807                                 null, null, null, null, null, null, null));
808             }
809         }
810     }
811 
812     /**
813      * Updates the last fill response when a dataset is shown.
814      */
logDatasetShown(int sessionId, @Nullable Bundle clientState)815     void logDatasetShown(int sessionId, @Nullable Bundle clientState) {
816         synchronized (mLock) {
817             if (isValidEventLocked("logDatasetShown", sessionId)) {
818                 mEventHistory.addEvent(
819                         new Event(Event.TYPE_DATASETS_SHOWN, null, clientState, null, null, null,
820                                 null, null, null, null, null));
821             }
822         }
823     }
824 
logAugmentedAutofillAuthenticationSelected(int sessionId, @Nullable String selectedDataset, @Nullable Bundle clientState)825     void logAugmentedAutofillAuthenticationSelected(int sessionId, @Nullable String selectedDataset,
826             @Nullable Bundle clientState) {
827         synchronized (mLock) {
828             if (mAugmentedAutofillEventHistory == null
829                     || mAugmentedAutofillEventHistory.getSessionId() != sessionId) {
830                 return;
831             }
832             mAugmentedAutofillEventHistory.addEvent(
833                     new Event(Event.TYPE_DATASET_AUTHENTICATION_SELECTED, selectedDataset,
834                             clientState, null, null, null, null, null, null, null, null));
835         }
836     }
837 
logAugmentedAutofillSelected(int sessionId, @Nullable String suggestionId, @Nullable Bundle clientState)838     void logAugmentedAutofillSelected(int sessionId, @Nullable String suggestionId,
839             @Nullable Bundle clientState) {
840         synchronized (mLock) {
841             if (mAugmentedAutofillEventHistory == null
842                     || mAugmentedAutofillEventHistory.getSessionId() != sessionId) {
843                 return;
844             }
845             mAugmentedAutofillEventHistory.addEvent(
846                     new Event(Event.TYPE_DATASET_SELECTED, suggestionId, clientState, null, null,
847                             null, null, null, null, null, null));
848         }
849     }
850 
logAugmentedAutofillShown(int sessionId, @Nullable Bundle clientState)851     void logAugmentedAutofillShown(int sessionId, @Nullable Bundle clientState) {
852         synchronized (mLock) {
853             if (mAugmentedAutofillEventHistory == null
854                     || mAugmentedAutofillEventHistory.getSessionId() != sessionId) {
855                 return;
856             }
857             mAugmentedAutofillEventHistory.addEvent(
858                     new Event(Event.TYPE_DATASETS_SHOWN, null, clientState, null, null, null,
859                             null, null, null, null, null));
860 
861         }
862     }
863 
864     /**
865      * Updates the last fill response when an autofill context is committed.
866      */
867     @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)868     void logContextCommittedLocked(int sessionId, @Nullable Bundle clientState,
869             @Nullable ArrayList<String> selectedDatasets,
870             @Nullable ArraySet<String> ignoredDatasets,
871             @Nullable ArrayList<AutofillId> changedFieldIds,
872             @Nullable ArrayList<String> changedDatasetIds,
873             @Nullable ArrayList<AutofillId> manuallyFilledFieldIds,
874             @Nullable ArrayList<ArrayList<String>> manuallyFilledDatasetIds,
875             @NonNull ComponentName appComponentName, boolean compatMode) {
876         logContextCommittedLocked(sessionId, clientState, selectedDatasets, ignoredDatasets,
877                 changedFieldIds, changedDatasetIds, manuallyFilledFieldIds,
878                 manuallyFilledDatasetIds, /* detectedFieldIdsList= */ null,
879                 /* detectedFieldClassificationsList= */ null, appComponentName, compatMode,
880                 Event.NO_SAVE_UI_REASON_NONE);
881     }
882 
883     @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)884     void logContextCommittedLocked(int sessionId, @Nullable Bundle clientState,
885             @Nullable ArrayList<String> selectedDatasets,
886             @Nullable ArraySet<String> ignoredDatasets,
887             @Nullable ArrayList<AutofillId> changedFieldIds,
888             @Nullable ArrayList<String> changedDatasetIds,
889             @Nullable ArrayList<AutofillId> manuallyFilledFieldIds,
890             @Nullable ArrayList<ArrayList<String>> manuallyFilledDatasetIds,
891             @Nullable ArrayList<AutofillId> detectedFieldIdsList,
892             @Nullable ArrayList<FieldClassification> detectedFieldClassificationsList,
893             @NonNull ComponentName appComponentName, boolean compatMode,
894             @NoSaveReason int saveDialogNotShowReason) {
895         if (isValidEventLocked("logDatasetNotSelected()", sessionId)) {
896             if (sVerbose) {
897                 Slog.v(TAG, "logContextCommitted() with FieldClassification: id=" + sessionId
898                         + ", selectedDatasets=" + selectedDatasets
899                         + ", ignoredDatasetIds=" + ignoredDatasets
900                         + ", changedAutofillIds=" + changedFieldIds
901                         + ", changedDatasetIds=" + changedDatasetIds
902                         + ", manuallyFilledFieldIds=" + manuallyFilledFieldIds
903                         + ", detectedFieldIds=" + detectedFieldIdsList
904                         + ", detectedFieldClassifications=" + detectedFieldClassificationsList
905                         + ", appComponentName=" + appComponentName.toShortString()
906                         + ", compatMode=" + compatMode
907                         + ", saveDialogNotShowReason=" + saveDialogNotShowReason);
908             }
909             AutofillId[] detectedFieldsIds = null;
910             FieldClassification[] detectedFieldClassifications = null;
911             if (detectedFieldIdsList != null) {
912                 detectedFieldsIds = new AutofillId[detectedFieldIdsList.size()];
913                 detectedFieldIdsList.toArray(detectedFieldsIds);
914                 detectedFieldClassifications =
915                         new FieldClassification[detectedFieldClassificationsList.size()];
916                 detectedFieldClassificationsList.toArray(detectedFieldClassifications);
917 
918                 final int numberFields = detectedFieldsIds.length;
919                 int totalSize = 0;
920                 float totalScore = 0;
921                 for (int i = 0; i < numberFields; i++) {
922                     final FieldClassification fc = detectedFieldClassifications[i];
923                     final List<Match> matches = fc.getMatches();
924                     final int size = matches.size();
925                     totalSize += size;
926                     for (int j = 0; j < size; j++) {
927                         totalScore += matches.get(j).getScore();
928                     }
929                 }
930 
931                 final int averageScore = (int) ((totalScore * 100) / totalSize);
932                 mMetricsLogger.write(Helper
933                         .newLogMaker(MetricsEvent.AUTOFILL_FIELD_CLASSIFICATION_MATCHES,
934                                 appComponentName, getServicePackageName(), sessionId, compatMode)
935                         .setCounterValue(numberFields)
936                         .addTaggedData(MetricsEvent.FIELD_AUTOFILL_MATCH_SCORE,
937                                 averageScore));
938             }
939             mEventHistory.addEvent(new Event(Event.TYPE_CONTEXT_COMMITTED, null,
940                     clientState, selectedDatasets, ignoredDatasets,
941                     changedFieldIds, changedDatasetIds,
942                     manuallyFilledFieldIds, manuallyFilledDatasetIds,
943                     detectedFieldsIds, detectedFieldClassifications, saveDialogNotShowReason));
944         }
945     }
946 
947     /**
948      * Gets the fill event history.
949      *
950      * @param callingUid The calling uid
951      * @return The history for the autofill or the augmented autofill events depending on the {@code
952      * callingUid}, or {@code null} if there is none.
953      */
getFillEventHistory(int callingUid)954     FillEventHistory getFillEventHistory(int callingUid) {
955         synchronized (mLock) {
956             if (mEventHistory != null
957                     && isCalledByServiceLocked("getFillEventHistory", callingUid)) {
958                 return mEventHistory;
959             }
960             if (mAugmentedAutofillEventHistory != null && isCalledByAugmentedAutofillServiceLocked(
961                     "getFillEventHistory", callingUid)) {
962                 return mAugmentedAutofillEventHistory;
963             }
964         }
965         return null;
966     }
967 
968     // Called by Session - does not need to check uid
getUserData()969     UserData getUserData() {
970         synchronized (mLock) {
971             return mUserData;
972         }
973     }
974 
975     // Called by AutofillManager
getUserData(int callingUid)976     UserData getUserData(int callingUid) {
977         synchronized (mLock) {
978             if (isCalledByServiceLocked("getUserData", callingUid)) {
979                 return mUserData;
980             }
981         }
982         return null;
983     }
984 
985     // Called by AutofillManager
setUserData(int callingUid, UserData userData)986     void setUserData(int callingUid, UserData userData) {
987         synchronized (mLock) {
988             if (!isCalledByServiceLocked("setUserData", callingUid)) {
989                 return;
990             }
991             mUserData = userData;
992             // Log it
993             final int numberFields = mUserData == null ? 0: mUserData.getCategoryIds().length;
994             // NOTE: contrary to most metrics, the service name is logged as the main package name
995             // here, not as MetricsEvent.FIELD_AUTOFILL_SERVICE
996             mMetricsLogger.write(new LogMaker(MetricsEvent.AUTOFILL_USERDATA_UPDATED)
997                     .setPackageName(getServicePackageName())
998                     .addTaggedData(MetricsEvent.FIELD_AUTOFILL_NUM_VALUES, numberFields));
999         }
1000     }
1001 
1002     @GuardedBy("mLock")
isCalledByServiceLocked(@onNull String methodName, int callingUid)1003     private boolean isCalledByServiceLocked(@NonNull String methodName, int callingUid) {
1004         final int serviceUid = getServiceUidLocked();
1005         if (serviceUid != callingUid) {
1006             Slog.w(TAG, methodName + "() called by UID " + callingUid
1007                     + ", but service UID is " + serviceUid);
1008             return false;
1009         }
1010         return true;
1011     }
1012 
1013     @GuardedBy("mLock")
getSupportedSmartSuggestionModesLocked()1014     @SmartSuggestionMode int getSupportedSmartSuggestionModesLocked() {
1015         return mMaster.getSupportedSmartSuggestionModesLocked();
1016     }
1017 
1018     @Override
1019     @GuardedBy("mLock")
dumpLocked(String prefix, PrintWriter pw)1020     protected void dumpLocked(String prefix, PrintWriter pw) {
1021         super.dumpLocked(prefix, pw);
1022 
1023         final String prefix2 = prefix + "  ";
1024 
1025         pw.print(prefix); pw.print("UID: "); pw.println(getServiceUidLocked());
1026         pw.print(prefix); pw.print("Autofill Service Info: ");
1027         if (mInfo == null) {
1028             pw.println("N/A");
1029         } else {
1030             pw.println();
1031             mInfo.dump(prefix2, pw);
1032         }
1033         pw.print(prefix); pw.print("Default component: "); pw.println(getContext()
1034                 .getString(R.string.config_defaultAutofillService));
1035 
1036         pw.print(prefix); pw.println("mAugmentedAutofillNamer: ");
1037         pw.print(prefix2); mMaster.mAugmentedAutofillResolver.dumpShort(pw, mUserId); pw.println();
1038 
1039         if (mRemoteAugmentedAutofillService != null) {
1040             pw.print(prefix); pw.println("RemoteAugmentedAutofillService: ");
1041             mRemoteAugmentedAutofillService.dump(prefix2, pw);
1042         }
1043         if (mRemoteAugmentedAutofillServiceInfo != null) {
1044             pw.print(prefix); pw.print("RemoteAugmentedAutofillServiceInfo: ");
1045             pw.println(mRemoteAugmentedAutofillServiceInfo);
1046         }
1047 
1048         pw.print(prefix); pw.print("Field classification enabled: ");
1049             pw.println(isFieldClassificationEnabledLocked());
1050         pw.print(prefix); pw.print("Compat pkgs: ");
1051         final ArrayMap<String, Long> compatPkgs = getCompatibilityPackagesLocked();
1052         if (compatPkgs == null) {
1053             pw.println("N/A");
1054         } else {
1055             pw.println(compatPkgs);
1056         }
1057         pw.print(prefix); pw.print("Inline Suggestions Enabled: ");
1058         pw.println(isInlineSuggestionsEnabledLocked());
1059         pw.print(prefix); pw.print("Last prune: "); pw.println(mLastPrune);
1060 
1061         mDisabledInfoCache.dump(mUserId, prefix, pw);
1062 
1063         final int size = mSessions.size();
1064         if (size == 0) {
1065             pw.print(prefix); pw.println("No sessions");
1066         } else {
1067             pw.print(prefix); pw.print(size); pw.println(" sessions:");
1068             for (int i = 0; i < size; i++) {
1069                 pw.print(prefix); pw.print("#"); pw.println(i + 1);
1070                 mSessions.valueAt(i).dumpLocked(prefix2, pw);
1071             }
1072         }
1073 
1074         pw.print(prefix); pw.print("Clients: ");
1075         if (mClients == null) {
1076             pw.println("N/A");
1077         } else {
1078             pw.println();
1079             mClients.dump(pw, prefix2);
1080         }
1081 
1082         if (mEventHistory == null || mEventHistory.getEvents() == null
1083                 || mEventHistory.getEvents().size() == 0) {
1084             pw.print(prefix); pw.println("No event on last fill response");
1085         } else {
1086             pw.print(prefix); pw.println("Events of last fill response:");
1087             pw.print(prefix);
1088 
1089             int numEvents = mEventHistory.getEvents().size();
1090             for (int i = 0; i < numEvents; i++) {
1091                 final Event event = mEventHistory.getEvents().get(i);
1092                 pw.println("  " + i + ": eventType=" + event.getType() + " datasetId="
1093                         + event.getDatasetId());
1094             }
1095         }
1096 
1097         pw.print(prefix); pw.print("User data: ");
1098         if (mUserData == null) {
1099             pw.println("N/A");
1100         } else {
1101             pw.println();
1102             mUserData.dump(prefix2, pw);
1103         }
1104 
1105         pw.print(prefix); pw.println("Field Classification strategy: ");
1106         mFieldClassificationStrategy.dump(prefix2, pw);
1107     }
1108 
1109     @GuardedBy("mLock")
forceRemoveAllSessionsLocked()1110     void forceRemoveAllSessionsLocked() {
1111         final int sessionCount = mSessions.size();
1112         if (sessionCount == 0) {
1113             mUi.destroyAll(null, null, false);
1114             return;
1115         }
1116 
1117         for (int i = sessionCount - 1; i >= 0; i--) {
1118             mSessions.valueAt(i).forceRemoveFromServiceLocked();
1119         }
1120     }
1121 
1122     @GuardedBy("mLock")
forceRemoveForAugmentedOnlySessionsLocked()1123     void forceRemoveForAugmentedOnlySessionsLocked() {
1124         final int sessionCount = mSessions.size();
1125         for (int i = sessionCount - 1; i >= 0; i--) {
1126             mSessions.valueAt(i).forceRemoveFromServiceIfForAugmentedOnlyLocked();
1127         }
1128     }
1129 
1130     /**
1131      * This method is called exclusively in response to {@code Intent.ACTION_CLOSE_SYSTEM_DIALOGS}.
1132      * The method removes all sessions that are finished but showing SaveUI due to how SaveUI is
1133      * managed (see b/64940307). Otherwise it will remove any augmented autofill generated windows.
1134      */
1135     // TODO(b/64940307): remove this method if SaveUI is refactored to be attached on activities
1136     @GuardedBy("mLock")
forceRemoveFinishedSessionsLocked()1137     void forceRemoveFinishedSessionsLocked() {
1138         final int sessionCount = mSessions.size();
1139         for (int i = sessionCount - 1; i >= 0; i--) {
1140             final Session session = mSessions.valueAt(i);
1141             if (session.isSaveUiShowingLocked()) {
1142                 if (sDebug) Slog.d(TAG, "destroyFinishedSessionsLocked(): " + session.id);
1143                 session.forceRemoveFromServiceLocked();
1144             } else {
1145                 session.destroyAugmentedAutofillWindowsLocked();
1146             }
1147         }
1148     }
1149 
1150     @GuardedBy("mLock")
listSessionsLocked(ArrayList<String> output)1151     void listSessionsLocked(ArrayList<String> output) {
1152         final int numSessions = mSessions.size();
1153         if (numSessions <= 0) return;
1154 
1155         final String fmt = "%d:%s:%s";
1156         for (int i = 0; i < numSessions; i++) {
1157             final int id = mSessions.keyAt(i);
1158             final String service = mInfo == null
1159                     ? "no_svc"
1160                     : mInfo.getServiceInfo().getComponentName().flattenToShortString();
1161             final String augmentedService = mRemoteAugmentedAutofillServiceInfo == null
1162                     ? "no_aug"
1163                     : mRemoteAugmentedAutofillServiceInfo.getComponentName().flattenToShortString();
1164             output.add(String.format(fmt, id, service, augmentedService));
1165         }
1166     }
1167 
1168     @GuardedBy("mLock")
getCompatibilityPackagesLocked()1169     @Nullable ArrayMap<String, Long> getCompatibilityPackagesLocked() {
1170         if (mInfo != null) {
1171             return mInfo.getCompatibilityPackages();
1172         }
1173         return null;
1174     }
1175 
1176     @GuardedBy("mLock")
isInlineSuggestionsEnabledLocked()1177     boolean isInlineSuggestionsEnabledLocked() {
1178         if (mInfo != null) {
1179             return mInfo.isInlineSuggestionsEnabled();
1180         }
1181         return false;
1182     }
1183 
1184     @GuardedBy("mLock")
requestSavedPasswordCount(IResultReceiver receiver)1185     void requestSavedPasswordCount(IResultReceiver receiver) {
1186         RemoteFillService remoteService =
1187                 new RemoteFillService(
1188                         getContext(), mInfo.getServiceInfo().getComponentName(), mUserId,
1189                         /* callbacks= */ null, mMaster.isInstantServiceAllowed());
1190         remoteService.onSavedPasswordCountRequest(receiver);
1191     }
1192 
1193     @GuardedBy("mLock")
getRemoteAugmentedAutofillServiceLocked()1194     @Nullable RemoteAugmentedAutofillService getRemoteAugmentedAutofillServiceLocked() {
1195         if (mRemoteAugmentedAutofillService == null) {
1196             final String serviceName = mMaster.mAugmentedAutofillResolver.getServiceName(mUserId);
1197             if (serviceName == null) {
1198                 if (mMaster.verbose) {
1199                     Slog.v(TAG, "getRemoteAugmentedAutofillServiceLocked(): not set");
1200                 }
1201                 return null;
1202             }
1203             final Pair<ServiceInfo, ComponentName> pair = RemoteAugmentedAutofillService
1204                     .getComponentName(serviceName, mUserId,
1205                             mMaster.mAugmentedAutofillResolver.isTemporary(mUserId));
1206             if (pair == null) return null;
1207 
1208             mRemoteAugmentedAutofillServiceInfo = pair.first;
1209             final ComponentName componentName = pair.second;
1210             if (sVerbose) {
1211                 Slog.v(TAG, "getRemoteAugmentedAutofillServiceLocked(): " + componentName);
1212             }
1213 
1214             final RemoteAugmentedAutofillServiceCallbacks callbacks =
1215                     new RemoteAugmentedAutofillServiceCallbacks() {
1216                         @Override
1217                         public void resetLastResponse() {
1218                             AutofillManagerServiceImpl.this.resetLastAugmentedAutofillResponse();
1219                         }
1220 
1221                         @Override
1222                         public void setLastResponse(int sessionId) {
1223                             AutofillManagerServiceImpl.this.setLastAugmentedAutofillResponse(
1224                                     sessionId);
1225                         }
1226 
1227                         @Override
1228                         public void logAugmentedAutofillShown(int sessionId, Bundle clientState) {
1229                             AutofillManagerServiceImpl.this.logAugmentedAutofillShown(sessionId,
1230                                     clientState);
1231                         }
1232 
1233                         @Override
1234                         public void logAugmentedAutofillSelected(int sessionId,
1235                                 String suggestionId, Bundle clientState) {
1236                             AutofillManagerServiceImpl.this.logAugmentedAutofillSelected(sessionId,
1237                                     suggestionId, clientState);
1238                         }
1239 
1240                         @Override
1241                         public void logAugmentedAutofillAuthenticationSelected(int sessionId,
1242                                 String suggestionId, Bundle clientState) {
1243                             AutofillManagerServiceImpl.this
1244                                     .logAugmentedAutofillAuthenticationSelected(
1245                                             sessionId, suggestionId, clientState);
1246                         }
1247 
1248                         @Override
1249                         public void onServiceDied(@NonNull RemoteAugmentedAutofillService service) {
1250                             Slog.w(TAG, "remote augmented autofill service died");
1251                             final RemoteAugmentedAutofillService remoteService =
1252                                     mRemoteAugmentedAutofillService;
1253                             if (remoteService != null) {
1254                                 remoteService.unbind();
1255                             }
1256                             mRemoteAugmentedAutofillService = null;
1257                         }
1258                     };
1259             final int serviceUid = mRemoteAugmentedAutofillServiceInfo.applicationInfo.uid;
1260             mRemoteAugmentedAutofillService = new RemoteAugmentedAutofillService(getContext(),
1261                     serviceUid, componentName,
1262                     mUserId, callbacks, mMaster.isInstantServiceAllowed(),
1263                     mMaster.verbose, mMaster.mAugmentedServiceIdleUnbindTimeoutMs,
1264                     mMaster.mAugmentedServiceRequestTimeoutMs);
1265         }
1266 
1267         return mRemoteAugmentedAutofillService;
1268     }
1269 
1270     @GuardedBy("mLock")
getRemoteAugmentedAutofillServiceIfCreatedLocked()1271     @Nullable RemoteAugmentedAutofillService getRemoteAugmentedAutofillServiceIfCreatedLocked() {
1272         return mRemoteAugmentedAutofillService;
1273     }
1274 
1275     /**
1276      * Called when the {@link AutofillManagerService#mAugmentedAutofillResolver}
1277      * changed (among other places).
1278      */
updateRemoteAugmentedAutofillService()1279     void updateRemoteAugmentedAutofillService() {
1280         synchronized (mLock) {
1281             if (mRemoteAugmentedAutofillService != null) {
1282                 if (sVerbose) {
1283                     Slog.v(TAG, "updateRemoteAugmentedAutofillService(): "
1284                             + "destroying old remote service");
1285                 }
1286                 forceRemoveForAugmentedOnlySessionsLocked();
1287                 mRemoteAugmentedAutofillService.unbind();
1288                 mRemoteAugmentedAutofillService = null;
1289                 mRemoteAugmentedAutofillServiceInfo = null;
1290                 resetAugmentedAutofillWhitelistLocked();
1291             }
1292 
1293             final boolean available = isAugmentedAutofillServiceAvailableLocked();
1294             if (sVerbose) Slog.v(TAG, "updateRemoteAugmentedAutofillService(): " + available);
1295 
1296             if (available) {
1297                 mRemoteAugmentedAutofillService = getRemoteAugmentedAutofillServiceLocked();
1298             }
1299         }
1300     }
1301 
isAugmentedAutofillServiceAvailableLocked()1302     private boolean isAugmentedAutofillServiceAvailableLocked() {
1303         if (mMaster.verbose) {
1304             Slog.v(TAG, "isAugmentedAutofillService(): "
1305                     + "setupCompleted=" + isSetupCompletedLocked()
1306                     + ", disabled=" + isDisabledByUserRestrictionsLocked()
1307                     + ", augmentedService="
1308                     + mMaster.mAugmentedAutofillResolver.getServiceName(mUserId));
1309         }
1310         if (!isSetupCompletedLocked() || isDisabledByUserRestrictionsLocked()
1311                 || mMaster.mAugmentedAutofillResolver.getServiceName(mUserId) == null) {
1312             return false;
1313         }
1314         return true;
1315     }
1316 
isAugmentedAutofillServiceForUserLocked(int callingUid)1317     boolean isAugmentedAutofillServiceForUserLocked(int callingUid) {
1318         return mRemoteAugmentedAutofillServiceInfo != null
1319                 && mRemoteAugmentedAutofillServiceInfo.applicationInfo.uid == callingUid;
1320     }
1321 
1322     /**
1323      * Sets which packages and activities can trigger augmented autofill.
1324      *
1325      * @return whether caller UID is the augmented autofill service for the user
1326      */
1327     @GuardedBy("mLock")
setAugmentedAutofillWhitelistLocked(@ullable List<String> packages, @Nullable List<ComponentName> activities, int callingUid)1328     boolean setAugmentedAutofillWhitelistLocked(@Nullable List<String> packages,
1329             @Nullable List<ComponentName> activities, int callingUid) {
1330 
1331         if (!isCalledByAugmentedAutofillServiceLocked("setAugmentedAutofillWhitelistLocked",
1332                 callingUid)) {
1333             return false;
1334         }
1335         if (mMaster.verbose) {
1336             Slog.v(TAG, "setAugmentedAutofillWhitelistLocked(packages=" + packages + ", activities="
1337                     + activities + ")");
1338         }
1339         whitelistForAugmentedAutofillPackages(packages, activities);
1340         final String serviceName;
1341         if (mRemoteAugmentedAutofillServiceInfo != null) {
1342             serviceName = mRemoteAugmentedAutofillServiceInfo.getComponentName()
1343                     .flattenToShortString();
1344         } else {
1345             Slog.e(TAG, "setAugmentedAutofillWhitelistLocked(): no service");
1346             serviceName = "N/A";
1347         }
1348 
1349         final LogMaker log = new LogMaker(MetricsEvent.AUTOFILL_AUGMENTED_WHITELIST_REQUEST)
1350                 .addTaggedData(MetricsEvent.FIELD_AUTOFILL_SERVICE, serviceName);
1351         if (packages != null) {
1352             log.addTaggedData(MetricsEvent.FIELD_AUTOFILL_NUMBER_PACKAGES, packages.size());
1353         }
1354         if (activities != null) {
1355             log.addTaggedData(MetricsEvent.FIELD_AUTOFILL_NUMBER_ACTIVITIES, activities.size());
1356         }
1357         mMetricsLogger.write(log);
1358 
1359         return true;
1360     }
1361 
1362     @GuardedBy("mLock")
isCalledByAugmentedAutofillServiceLocked(@onNull String methodName, int callingUid)1363     private boolean isCalledByAugmentedAutofillServiceLocked(@NonNull String methodName,
1364             int callingUid) {
1365         // Lazy load service first
1366         final RemoteAugmentedAutofillService service = getRemoteAugmentedAutofillServiceLocked();
1367         if (service == null) {
1368             Slog.w(TAG, methodName + "() called by UID " + callingUid
1369                     + ", but there is no augmented autofill service defined for user "
1370                     + getUserId());
1371             return false;
1372         }
1373 
1374         if (getAugmentedAutofillServiceUidLocked() != callingUid) {
1375             Slog.w(TAG, methodName + "() called by UID " + callingUid
1376                     + ", but service UID is " + getAugmentedAutofillServiceUidLocked()
1377                     + " for user " + getUserId());
1378             return false;
1379         }
1380         return true;
1381     }
1382 
1383     @GuardedBy("mLock")
getAugmentedAutofillServiceUidLocked()1384     private int getAugmentedAutofillServiceUidLocked() {
1385         if (mRemoteAugmentedAutofillServiceInfo == null) {
1386             if (mMaster.verbose) {
1387                 Slog.v(TAG, "getAugmentedAutofillServiceUid(): "
1388                         + "no mRemoteAugmentedAutofillServiceInfo");
1389             }
1390             return Process.INVALID_UID;
1391         }
1392         return mRemoteAugmentedAutofillServiceInfo.applicationInfo.uid;
1393     }
1394 
1395     @GuardedBy("mLock")
isWhitelistedForAugmentedAutofillLocked(@onNull ComponentName componentName)1396     boolean isWhitelistedForAugmentedAutofillLocked(@NonNull ComponentName componentName) {
1397         return mMaster.mAugmentedAutofillState.isWhitelisted(mUserId, componentName);
1398     }
1399 
1400     /**
1401      * @throws IllegalArgumentException if packages or components are empty.
1402      */
whitelistForAugmentedAutofillPackages(@ullable List<String> packages, @Nullable List<ComponentName> components)1403     private void whitelistForAugmentedAutofillPackages(@Nullable List<String> packages,
1404             @Nullable List<ComponentName> components) {
1405         // TODO(b/123100824): add CTS test for when it's null
1406         synchronized (mLock) {
1407             if (mMaster.verbose) {
1408                 Slog.v(TAG, "whitelisting packages: " + packages + "and activities: " + components);
1409             }
1410             mMaster.mAugmentedAutofillState.setWhitelist(mUserId, packages, components);
1411         }
1412     }
1413 
1414     /**
1415      * Resets the augmented autofill allowlist.
1416      */
1417     @GuardedBy("mLock")
resetAugmentedAutofillWhitelistLocked()1418     void resetAugmentedAutofillWhitelistLocked() {
1419         if (mMaster.verbose) {
1420             Slog.v(TAG, "resetting augmented autofill whitelist");
1421         }
1422         mMaster.mAugmentedAutofillState.resetWhitelist(mUserId);
1423     }
1424 
sendStateToClients(boolean resetClient)1425     private void sendStateToClients(boolean resetClient) {
1426         final RemoteCallbackList<IAutoFillManagerClient> clients;
1427         final int userClientCount;
1428         synchronized (mLock) {
1429             if (mClients == null) {
1430                 return;
1431             }
1432             clients = mClients;
1433             userClientCount = clients.beginBroadcast();
1434         }
1435         try {
1436             for (int i = 0; i < userClientCount; i++) {
1437                 final IAutoFillManagerClient client = clients.getBroadcastItem(i);
1438                 try {
1439                     final boolean resetSession;
1440                     final boolean isEnabled;
1441                     synchronized (mLock) {
1442                         resetSession = resetClient || isClientSessionDestroyedLocked(client);
1443                         isEnabled = isEnabledLocked();
1444                     }
1445                     int flags = 0;
1446                     if (isEnabled) {
1447                         flags |= AutofillManager.SET_STATE_FLAG_ENABLED;
1448                     }
1449                     if (resetSession) {
1450                         flags |= AutofillManager.SET_STATE_FLAG_RESET_SESSION;
1451                     }
1452                     if (resetClient) {
1453                         flags |= AutofillManager.SET_STATE_FLAG_RESET_CLIENT;
1454                     }
1455                     if (sDebug) {
1456                         flags |= AutofillManager.SET_STATE_FLAG_DEBUG;
1457                     }
1458                     if (sVerbose) {
1459                         flags |= AutofillManager.SET_STATE_FLAG_VERBOSE;
1460                     }
1461                     client.setState(flags);
1462                 } catch (RemoteException re) {
1463                     /* ignore */
1464                 }
1465             }
1466         } finally {
1467             clients.finishBroadcast();
1468         }
1469     }
1470 
1471     @GuardedBy("mLock")
isClientSessionDestroyedLocked(IAutoFillManagerClient client)1472     private boolean isClientSessionDestroyedLocked(IAutoFillManagerClient client) {
1473         final int sessionCount = mSessions.size();
1474         for (int i = 0; i < sessionCount; i++) {
1475             final Session session = mSessions.valueAt(i);
1476             if (session.getClient().equals(client)) {
1477                 return session.isDestroyed();
1478             }
1479         }
1480         return true;
1481     }
1482 
1483     /**
1484      * Called by {@link Session} when service asked to disable autofill for an app.
1485      */
disableAutofillForApp(@onNull String packageName, long duration, int sessionId, boolean compatMode)1486     void disableAutofillForApp(@NonNull String packageName, long duration, int sessionId,
1487             boolean compatMode) {
1488         synchronized (mLock) {
1489             long expiration = SystemClock.elapsedRealtime() + duration;
1490             // Protect it against overflow
1491             if (expiration < 0) {
1492                 expiration = Long.MAX_VALUE;
1493             }
1494             mDisabledInfoCache.addDisabledAppLocked(mUserId, packageName, expiration);
1495 
1496             int intDuration = duration > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) duration;
1497             mMetricsLogger.write(Helper.newLogMaker(MetricsEvent.AUTOFILL_SERVICE_DISABLED_APP,
1498                     packageName, getServicePackageName(), sessionId, compatMode)
1499                     .addTaggedData(MetricsEvent.FIELD_AUTOFILL_DURATION, intDuration));
1500         }
1501     }
1502 
1503     /**
1504      * Called by {@link Session} when service asked to disable autofill an app.
1505      */
disableAutofillForActivity(@onNull ComponentName componentName, long duration, int sessionId, boolean compatMode)1506     void disableAutofillForActivity(@NonNull ComponentName componentName, long duration,
1507             int sessionId, boolean compatMode) {
1508         synchronized (mLock) {
1509             long expiration = SystemClock.elapsedRealtime() + duration;
1510             // Protect it against overflow
1511             if (expiration < 0) {
1512                 expiration = Long.MAX_VALUE;
1513             }
1514             mDisabledInfoCache.addDisabledActivityLocked(mUserId, componentName, expiration);
1515             final int intDuration = duration > Integer.MAX_VALUE
1516                     ? Integer.MAX_VALUE
1517                     : (int) duration;
1518 
1519             final LogMaker log = Helper.newLogMaker(MetricsEvent.AUTOFILL_SERVICE_DISABLED_ACTIVITY,
1520                     componentName, getServicePackageName(), sessionId, compatMode)
1521                     .addTaggedData(MetricsEvent.FIELD_AUTOFILL_DURATION, intDuration);
1522             mMetricsLogger.write(log);
1523         }
1524     }
1525 
1526     /**
1527      * Checks if autofill is disabled by service to the given activity.
1528      */
1529     @GuardedBy("mLock")
isAutofillDisabledLocked(@onNull ComponentName componentName)1530     private boolean isAutofillDisabledLocked(@NonNull ComponentName componentName) {
1531         return mDisabledInfoCache.isAutofillDisabledLocked(mUserId, componentName);
1532     }
1533 
1534     // Called by AutofillManager, checks UID.
isFieldClassificationEnabled(int callingUid)1535     boolean isFieldClassificationEnabled(int callingUid) {
1536         synchronized (mLock) {
1537             if (!isCalledByServiceLocked("isFieldClassificationEnabled", callingUid)) {
1538                 return false;
1539             }
1540             return isFieldClassificationEnabledLocked();
1541         }
1542     }
1543 
1544     // Called by internally, no need to check UID.
isFieldClassificationEnabledLocked()1545     boolean isFieldClassificationEnabledLocked() {
1546         return Settings.Secure.getIntForUser(
1547                 getContext().getContentResolver(),
1548                 Settings.Secure.AUTOFILL_FEATURE_FIELD_CLASSIFICATION, 1,
1549                 mUserId) == 1;
1550     }
1551 
getFieldClassificationStrategy()1552     FieldClassificationStrategy getFieldClassificationStrategy() {
1553         return mFieldClassificationStrategy;
1554     }
1555 
getAvailableFieldClassificationAlgorithms(int callingUid)1556     String[] getAvailableFieldClassificationAlgorithms(int callingUid) {
1557         synchronized (mLock) {
1558             if (!isCalledByServiceLocked("getFCAlgorithms()", callingUid)) {
1559                 return null;
1560             }
1561         }
1562         return mFieldClassificationStrategy.getAvailableAlgorithms();
1563     }
1564 
getDefaultFieldClassificationAlgorithm(int callingUid)1565     String getDefaultFieldClassificationAlgorithm(int callingUid) {
1566         synchronized (mLock) {
1567             if (!isCalledByServiceLocked("getDefaultFCAlgorithm()", callingUid)) {
1568                 return null;
1569             }
1570         }
1571         return mFieldClassificationStrategy.getDefaultAlgorithm();
1572     }
1573 
updateRemoteInlineSuggestionRenderServiceLocked()1574     private void updateRemoteInlineSuggestionRenderServiceLocked() {
1575         if (mRemoteInlineSuggestionRenderService != null) {
1576             if (sVerbose) {
1577                 Slog.v(TAG, "updateRemoteInlineSuggestionRenderService(): "
1578                         + "destroying old remote service");
1579             }
1580             mRemoteInlineSuggestionRenderService = null;
1581         }
1582 
1583         mRemoteInlineSuggestionRenderService = getRemoteInlineSuggestionRenderServiceLocked();
1584     }
1585 
getRemoteInlineSuggestionRenderServiceLocked()1586     @Nullable RemoteInlineSuggestionRenderService getRemoteInlineSuggestionRenderServiceLocked() {
1587         if (mRemoteInlineSuggestionRenderService == null) {
1588             final ComponentName componentName = RemoteInlineSuggestionRenderService
1589                 .getServiceComponentName(getContext(), mUserId);
1590             if (componentName == null) {
1591                 Slog.w(TAG, "No valid component found for InlineSuggestionRenderService");
1592                 return null;
1593             }
1594 
1595             mRemoteInlineSuggestionRenderService = new RemoteInlineSuggestionRenderService(
1596                     getContext(), componentName, InlineSuggestionRenderService.SERVICE_INTERFACE,
1597                     mUserId, new InlineSuggestionRenderCallbacksImpl(),
1598                     mMaster.isBindInstantServiceAllowed(), mMaster.verbose);
1599         }
1600 
1601         return mRemoteInlineSuggestionRenderService;
1602     }
1603 
1604     private class InlineSuggestionRenderCallbacksImpl implements
1605             RemoteInlineSuggestionRenderService.InlineSuggestionRenderCallbacks {
1606 
1607         @Override // from InlineSuggestionRenderCallbacksImpl
onServiceDied(@onNull RemoteInlineSuggestionRenderService service)1608         public void onServiceDied(@NonNull RemoteInlineSuggestionRenderService service) {
1609             // Don't do anything; eventually the system will bind to it again...
1610             Slog.w(TAG, "remote service died: " + service);
1611             mRemoteInlineSuggestionRenderService = null;
1612         }
1613     }
1614 
onSwitchInputMethod()1615     void onSwitchInputMethod() {
1616         synchronized (mLock) {
1617             final int sessionCount = mSessions.size();
1618             for (int i = 0; i < sessionCount; i++) {
1619                 final Session session = mSessions.valueAt(i);
1620                 session.onSwitchInputMethodLocked();
1621             }
1622         }
1623     }
1624 
1625     @Override
toString()1626     public String toString() {
1627         return "AutofillManagerServiceImpl: [userId=" + mUserId
1628                 + ", component=" + (mInfo != null
1629                 ? mInfo.getServiceInfo().getComponentName() : null) + "]";
1630     }
1631 
1632     /** Task used to prune abandoned session */
1633     private class PruneTask extends AsyncTask<Void, Void, Void> {
1634         @Override
doInBackground(Void... ignored)1635         protected Void doInBackground(Void... ignored) {
1636             int numSessionsToRemove;
1637 
1638             SparseArray<IBinder> sessionsToRemove;
1639 
1640             synchronized (mLock) {
1641                 numSessionsToRemove = mSessions.size();
1642                 sessionsToRemove = new SparseArray<>(numSessionsToRemove);
1643 
1644                 for (int i = 0; i < numSessionsToRemove; i++) {
1645                     Session session = mSessions.valueAt(i);
1646 
1647                     sessionsToRemove.put(session.id, session.getActivityTokenLocked());
1648                 }
1649             }
1650 
1651             final ActivityTaskManagerInternal atmInternal = LocalServices.getService(
1652                     ActivityTaskManagerInternal.class);
1653 
1654             // Only remove sessions which's activities are not known to the activity manager anymore
1655             for (int i = 0; i < numSessionsToRemove; i++) {
1656                 // The activity task manager cannot resolve activities that have been removed.
1657                 if (atmInternal.getActivityName(sessionsToRemove.valueAt(i)) != null) {
1658                     sessionsToRemove.removeAt(i);
1659                     i--;
1660                     numSessionsToRemove--;
1661                 }
1662             }
1663 
1664             synchronized (mLock) {
1665                 for (int i = 0; i < numSessionsToRemove; i++) {
1666                     Session sessionToRemove = mSessions.get(sessionsToRemove.keyAt(i));
1667 
1668                     if (sessionToRemove != null && sessionsToRemove.valueAt(i)
1669                             == sessionToRemove.getActivityTokenLocked()) {
1670                         if (sessionToRemove.isSaveUiShowingLocked()) {
1671                             if (sVerbose) {
1672                                 Slog.v(TAG, "Session " + sessionToRemove.id + " is saving");
1673                             }
1674                         } else {
1675                             if (sDebug) {
1676                                 Slog.i(TAG, "Prune session " + sessionToRemove.id + " ("
1677                                     + sessionToRemove.getActivityTokenLocked() + ")");
1678                             }
1679                             sessionToRemove.removeFromServiceLocked();
1680                         }
1681                     }
1682                 }
1683             }
1684 
1685             return null;
1686         }
1687     }
1688 }
1689