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