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