Home | History | Annotate | Download | only in autofill
      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.NO_SESSION;
     22 
     23 import static com.android.server.autofill.Helper.sDebug;
     24 import static com.android.server.autofill.Helper.sVerbose;
     25 
     26 import android.annotation.NonNull;
     27 import android.annotation.Nullable;
     28 import android.app.ActivityManager;
     29 import android.app.ActivityManagerInternal;
     30 import android.app.AppGlobals;
     31 import android.app.IActivityManager;
     32 import android.content.ComponentName;
     33 import android.content.Context;
     34 import android.content.pm.ApplicationInfo;
     35 import android.content.pm.PackageItemInfo;
     36 import android.content.pm.PackageManager;
     37 import android.content.pm.PackageManager.NameNotFoundException;
     38 import android.content.pm.ServiceInfo;
     39 import android.graphics.Rect;
     40 import android.graphics.drawable.Drawable;
     41 import android.metrics.LogMaker;
     42 import android.os.AsyncTask;
     43 import android.os.Binder;
     44 import android.os.Bundle;
     45 import android.os.Handler;
     46 import android.os.IBinder;
     47 import android.os.Looper;
     48 import android.os.RemoteCallbackList;
     49 import android.os.RemoteException;
     50 import android.os.SystemClock;
     51 import android.os.UserHandle;
     52 import android.os.UserManager;
     53 import android.provider.Settings;
     54 import android.service.autofill.AutofillService;
     55 import android.service.autofill.AutofillServiceInfo;
     56 import android.service.autofill.FieldClassification;
     57 import android.service.autofill.FieldClassification.Match;
     58 import android.service.autofill.FillEventHistory;
     59 import android.service.autofill.FillEventHistory.Event;
     60 import android.service.autofill.FillResponse;
     61 import android.service.autofill.IAutoFillService;
     62 import android.service.autofill.UserData;
     63 import android.text.TextUtils;
     64 import android.util.ArrayMap;
     65 import android.util.ArraySet;
     66 import android.util.DebugUtils;
     67 import android.util.LocalLog;
     68 import android.util.Slog;
     69 import android.util.SparseArray;
     70 import android.util.TimeUtils;
     71 import android.view.autofill.AutofillId;
     72 import android.view.autofill.AutofillManager;
     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.ui.AutoFillUI;
     83 
     84 import java.io.PrintWriter;
     85 import java.util.ArrayList;
     86 import java.util.List;
     87 import java.util.Random;
     88 
     89 /**
     90  * Bridge between the {@code system_server}'s {@link AutofillManagerService} and the
     91  * app's {@link IAutoFillService} implementation.
     92  *
     93  */
     94 final class AutofillManagerServiceImpl {
     95 
     96     private static final String TAG = "AutofillManagerServiceImpl";
     97     private static final int MAX_SESSION_ID_CREATE_TRIES = 2048;
     98 
     99     /** Minimum interval to prune abandoned sessions */
    100     private static final int MAX_ABANDONED_SESSION_MILLIS = 30000;
    101 
    102     private final int mUserId;
    103     private final Context mContext;
    104     private final Object mLock;
    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 mRequestsHistory;
    117     private final LocalLog mUiLatencyHistory;
    118     private final LocalLog mWtfHistory;
    119     private final FieldClassificationStrategy mFieldClassificationStrategy;
    120 
    121     /**
    122      * Apps disabled by the service; key is package name, value is when they will be enabled again.
    123      */
    124     @GuardedBy("mLock")
    125     private ArrayMap<String, Long> mDisabledApps;
    126 
    127     /**
    128      * Activities disabled by the service; key is component name, value is when they will be enabled
    129      * again.
    130      */
    131     @GuardedBy("mLock")
    132     private ArrayMap<ComponentName, Long> mDisabledActivities;
    133 
    134     /**
    135      * Whether service was disabled for user due to {@link UserManager} restrictions.
    136      */
    137     @GuardedBy("mLock")
    138     private boolean mDisabled;
    139 
    140     /**
    141      * Data used for field classification.
    142      */
    143     @GuardedBy("mLock")
    144     private UserData mUserData;
    145 
    146     /**
    147      * Caches whether the setup completed for the current user.
    148      */
    149     @GuardedBy("mLock")
    150     private boolean mSetupComplete;
    151 
    152     private final Handler mHandler = new Handler(Looper.getMainLooper(), null, true);
    153 
    154     /**
    155      * Cache of pending {@link Session}s, keyed by sessionId.
    156      *
    157      * <p>They're kept until the {@link AutofillService} finished handling a request, an error
    158      * occurs, or the session is abandoned.
    159      */
    160     @GuardedBy("mLock")
    161     private final SparseArray<Session> mSessions = new SparseArray<>();
    162 
    163     /** The last selection */
    164     @GuardedBy("mLock")
    165     private FillEventHistory mEventHistory;
    166 
    167     /** Shared instance, doesn't need to be logged */
    168     private final AutofillCompatState mAutofillCompatState;
    169 
    170     /** When was {@link PruneTask} last executed? */
    171     private long mLastPrune = 0;
    172 
    173     AutofillManagerServiceImpl(Context context, Object lock, LocalLog requestsHistory,
    174             LocalLog uiLatencyHistory, LocalLog wtfHistory, int userId, AutoFillUI ui,
    175             AutofillCompatState autofillCompatState, boolean disabled) {
    176         mContext = context;
    177         mLock = lock;
    178         mRequestsHistory = requestsHistory;
    179         mUiLatencyHistory = uiLatencyHistory;
    180         mWtfHistory = wtfHistory;
    181         mUserId = userId;
    182         mUi = ui;
    183         mFieldClassificationStrategy = new FieldClassificationStrategy(context, userId);
    184         mAutofillCompatState = autofillCompatState;
    185         updateLocked(disabled);
    186     }
    187 
    188     @Nullable
    189     CharSequence getServiceName() {
    190         final String packageName = getServicePackageName();
    191         if (packageName == null) {
    192             return null;
    193         }
    194 
    195         try {
    196             final PackageManager pm = mContext.getPackageManager();
    197             final ApplicationInfo info = pm.getApplicationInfo(packageName, 0);
    198             return pm.getApplicationLabel(info);
    199         } catch (Exception e) {
    200             Slog.e(TAG, "Could not get label for " + packageName + ": " + e);
    201             return packageName;
    202         }
    203     }
    204 
    205     @GuardedBy("mLock")
    206     private int getServiceUidLocked() {
    207         if (mInfo == null) {
    208             Slog.w(TAG,  "getServiceUidLocked(): no mInfo");
    209             return -1;
    210         }
    211         return mInfo.getServiceInfo().applicationInfo.uid;
    212     }
    213 
    214 
    215     @Nullable
    216     String[] getUrlBarResourceIdsForCompatMode(@NonNull String packageName) {
    217         return mAutofillCompatState.getUrlBarResourceIds(packageName, mUserId);
    218     }
    219 
    220     @Nullable
    221     String getServicePackageName() {
    222         final ComponentName serviceComponent = getServiceComponentName();
    223         if (serviceComponent != null) {
    224             return serviceComponent.getPackageName();
    225         }
    226         return null;
    227     }
    228 
    229     ComponentName getServiceComponentName() {
    230         synchronized (mLock) {
    231             if (mInfo == null) {
    232                 return null;
    233             }
    234             return mInfo.getServiceInfo().getComponentName();
    235         }
    236     }
    237 
    238     private boolean isSetupCompletedLocked() {
    239         final String setupComplete = Settings.Secure.getStringForUser(
    240                 mContext.getContentResolver(), Settings.Secure.USER_SETUP_COMPLETE, mUserId);
    241         return "1".equals(setupComplete);
    242     }
    243 
    244     private String getComponentNameFromSettings() {
    245         return Settings.Secure.getStringForUser(
    246                 mContext.getContentResolver(), Settings.Secure.AUTOFILL_SERVICE, mUserId);
    247     }
    248 
    249     @GuardedBy("mLock")
    250     void updateLocked(boolean disabled) {
    251         final boolean wasEnabled = isEnabledLocked();
    252         if (sVerbose) {
    253             Slog.v(TAG, "updateLocked(u=" + mUserId + "): wasEnabled=" + wasEnabled
    254                     + ", mSetupComplete= " + mSetupComplete
    255                     + ", disabled=" + disabled + ", mDisabled=" + mDisabled);
    256         }
    257         mSetupComplete = isSetupCompletedLocked();
    258         mDisabled = disabled;
    259         ComponentName serviceComponent = null;
    260         ServiceInfo serviceInfo = null;
    261         final String componentName = getComponentNameFromSettings();
    262         if (!TextUtils.isEmpty(componentName)) {
    263             try {
    264                 serviceComponent = ComponentName.unflattenFromString(componentName);
    265                 serviceInfo = AppGlobals.getPackageManager().getServiceInfo(serviceComponent,
    266                         0, mUserId);
    267                 if (serviceInfo == null) {
    268                     Slog.e(TAG, "Bad AutofillService name: " + componentName);
    269                 }
    270             } catch (RuntimeException | RemoteException e) {
    271                 Slog.e(TAG, "Error getting service info for '" + componentName + "': " + e);
    272                 serviceInfo = null;
    273             }
    274         }
    275         try {
    276             if (serviceInfo != null) {
    277                 mInfo = new AutofillServiceInfo(mContext, serviceComponent, mUserId);
    278                 if (sDebug) Slog.d(TAG, "Set component for user " + mUserId + " as " + mInfo);
    279             } else {
    280                 mInfo = null;
    281                 if (sDebug) {
    282                     Slog.d(TAG, "Reset component for user " + mUserId + " (" + componentName + ")");
    283                 }
    284             }
    285         } catch (Exception e) {
    286             Slog.e(TAG, "Bad AutofillServiceInfo for '" + componentName + "': " + e);
    287             mInfo = null;
    288         }
    289         final boolean isEnabled = isEnabledLocked();
    290         if (wasEnabled != isEnabled) {
    291             if (!isEnabled) {
    292                 final int sessionCount = mSessions.size();
    293                 for (int i = sessionCount - 1; i >= 0; i--) {
    294                     final Session session = mSessions.valueAt(i);
    295                     session.removeSelfLocked();
    296                 }
    297             }
    298             sendStateToClients(false);
    299         }
    300     }
    301 
    302     @GuardedBy("mLock")
    303     boolean addClientLocked(IAutoFillManagerClient client) {
    304         if (mClients == null) {
    305             mClients = new RemoteCallbackList<>();
    306         }
    307         mClients.register(client);
    308         return isEnabledLocked();
    309     }
    310 
    311     @GuardedBy("mLock")
    312     void removeClientLocked(IAutoFillManagerClient client) {
    313         if (mClients != null) {
    314             mClients.unregister(client);
    315         }
    316     }
    317 
    318     @GuardedBy("mLock")
    319     void setAuthenticationResultLocked(Bundle data, int sessionId, int authenticationId, int uid) {
    320         if (!isEnabledLocked()) {
    321             return;
    322         }
    323         final Session session = mSessions.get(sessionId);
    324         if (session != null && uid == session.uid) {
    325             session.setAuthenticationResultLocked(data, authenticationId);
    326         }
    327     }
    328 
    329     void setHasCallback(int sessionId, int uid, boolean hasIt) {
    330         if (!isEnabledLocked()) {
    331             return;
    332         }
    333         final Session session = mSessions.get(sessionId);
    334         if (session != null && uid == session.uid) {
    335             synchronized (mLock) {
    336                 session.setHasCallbackLocked(hasIt);
    337             }
    338         }
    339     }
    340 
    341     @GuardedBy("mLock")
    342     int startSessionLocked(@NonNull IBinder activityToken, int uid,
    343             @NonNull IBinder appCallbackToken, @NonNull AutofillId autofillId,
    344             @NonNull Rect virtualBounds, @Nullable AutofillValue value, boolean hasCallback,
    345             @NonNull ComponentName componentName, boolean compatMode,
    346             boolean bindInstantServiceAllowed, int flags) {
    347         if (!isEnabledLocked()) {
    348             return 0;
    349         }
    350 
    351         final String shortComponentName = componentName.toShortString();
    352 
    353         if (isAutofillDisabledLocked(componentName)) {
    354             if (sDebug) {
    355                 Slog.d(TAG, "startSession(" + shortComponentName
    356                         + "): ignored because disabled by service");
    357             }
    358 
    359             final IAutoFillManagerClient client = IAutoFillManagerClient.Stub
    360                     .asInterface(appCallbackToken);
    361             try {
    362                 client.setSessionFinished(AutofillManager.STATE_DISABLED_BY_SERVICE);
    363             } catch (RemoteException e) {
    364                 Slog.w(TAG, "Could not notify " + shortComponentName + " that it's disabled: " + e);
    365             }
    366 
    367             return NO_SESSION;
    368         }
    369 
    370         if (sVerbose) Slog.v(TAG, "startSession(): token=" + activityToken + ", flags=" + flags);
    371 
    372         // Occasionally clean up abandoned sessions
    373         pruneAbandonedSessionsLocked();
    374 
    375         final Session newSession = createSessionByTokenLocked(activityToken, uid, appCallbackToken,
    376                 hasCallback, componentName, compatMode, bindInstantServiceAllowed, flags);
    377         if (newSession == null) {
    378             return NO_SESSION;
    379         }
    380 
    381         final String historyItem =
    382                 "id=" + newSession.id + " uid=" + uid + " a=" + shortComponentName
    383                 + " s=" + mInfo.getServiceInfo().packageName
    384                 + " u=" + mUserId + " i=" + autofillId + " b=" + virtualBounds
    385                 + " hc=" + hasCallback + " f=" + flags;
    386         mRequestsHistory.log(historyItem);
    387 
    388         newSession.updateLocked(autofillId, virtualBounds, value, ACTION_START_SESSION, flags);
    389 
    390         return newSession.id;
    391     }
    392 
    393     /**
    394      * Remove abandoned sessions if needed.
    395      */
    396     @GuardedBy("mLock")
    397     private void pruneAbandonedSessionsLocked() {
    398         long now = System.currentTimeMillis();
    399         if (mLastPrune < now - MAX_ABANDONED_SESSION_MILLIS) {
    400             mLastPrune = now;
    401 
    402             if (mSessions.size() > 0) {
    403                 (new PruneTask()).execute();
    404             }
    405         }
    406     }
    407 
    408     @GuardedBy("mLock")
    409     void setAutofillFailureLocked(int sessionId, int uid, @NonNull List<AutofillId> ids) {
    410         if (!isEnabledLocked()) {
    411             return;
    412         }
    413         final Session session = mSessions.get(sessionId);
    414         if (session == null || uid != session.uid) {
    415             Slog.v(TAG, "setAutofillFailure(): no session for " + sessionId + "(" + uid + ")");
    416             return;
    417         }
    418         session.setAutofillFailureLocked(ids);
    419     }
    420 
    421     @GuardedBy("mLock")
    422     void finishSessionLocked(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             if (sVerbose) {
    430                 Slog.v(TAG, "finishSessionLocked(): no session for " + sessionId + "(" + uid + ")");
    431             }
    432             return;
    433         }
    434 
    435         session.logContextCommitted();
    436 
    437         final boolean finished = session.showSaveLocked();
    438         if (sVerbose) Slog.v(TAG, "finishSessionLocked(): session finished on save? " + finished);
    439 
    440         if (finished) {
    441             session.removeSelfLocked();
    442         }
    443     }
    444 
    445     @GuardedBy("mLock")
    446     void cancelSessionLocked(int sessionId, int uid) {
    447         if (!isEnabledLocked()) {
    448             return;
    449         }
    450 
    451         final Session session = mSessions.get(sessionId);
    452         if (session == null || uid != session.uid) {
    453             Slog.w(TAG, "cancelSessionLocked(): no session for " + sessionId + "(" + uid + ")");
    454             return;
    455         }
    456         session.removeSelfLocked();
    457     }
    458 
    459     @GuardedBy("mLock")
    460     void disableOwnedAutofillServicesLocked(int uid) {
    461         Slog.i(TAG, "disableOwnedServices(" + uid + "): " + mInfo);
    462         if (mInfo == null) return;
    463 
    464         final ServiceInfo serviceInfo = mInfo.getServiceInfo();
    465         if (serviceInfo.applicationInfo.uid != uid) {
    466             Slog.w(TAG, "disableOwnedServices(): ignored when called by UID " + uid
    467                     + " instead of " + serviceInfo.applicationInfo.uid
    468                     + " for service " + mInfo);
    469             return;
    470         }
    471 
    472 
    473         final long identity = Binder.clearCallingIdentity();
    474         try {
    475             final String autoFillService = getComponentNameFromSettings();
    476             final ComponentName componentName = serviceInfo.getComponentName();
    477             if (componentName.equals(ComponentName.unflattenFromString(autoFillService))) {
    478                 mMetricsLogger.action(MetricsEvent.AUTOFILL_SERVICE_DISABLED_SELF,
    479                         componentName.getPackageName());
    480                 Settings.Secure.putStringForUser(mContext.getContentResolver(),
    481                         Settings.Secure.AUTOFILL_SERVICE, null, mUserId);
    482                 destroySessionsLocked();
    483             } else {
    484                 Slog.w(TAG, "disableOwnedServices(): ignored because current service ("
    485                         + serviceInfo + ") does not match Settings (" + autoFillService + ")");
    486             }
    487         } finally {
    488             Binder.restoreCallingIdentity(identity);
    489         }
    490     }
    491 
    492     @GuardedBy("mLock")
    493     private Session createSessionByTokenLocked(@NonNull IBinder activityToken, int uid,
    494             @NonNull IBinder appCallbackToken, boolean hasCallback,
    495             @NonNull ComponentName componentName, boolean compatMode,
    496             boolean bindInstantServiceAllowed, int flags) {
    497         // use random ids so that one app cannot know that another app creates sessions
    498         int sessionId;
    499         int tries = 0;
    500         do {
    501             tries++;
    502             if (tries > MAX_SESSION_ID_CREATE_TRIES) {
    503                 Slog.w(TAG, "Cannot create session in " + MAX_SESSION_ID_CREATE_TRIES + " tries");
    504                 return null;
    505             }
    506 
    507             sessionId = sRandom.nextInt();
    508         } while (sessionId == NO_SESSION || mSessions.indexOfKey(sessionId) >= 0);
    509 
    510         assertCallerLocked(componentName, compatMode);
    511 
    512         final Session newSession = new Session(this, mUi, mContext, mHandler, mUserId, mLock,
    513                 sessionId, uid, activityToken, appCallbackToken, hasCallback, mUiLatencyHistory,
    514                 mWtfHistory, mInfo.getServiceInfo().getComponentName(), componentName, compatMode,
    515                 bindInstantServiceAllowed, flags);
    516         mSessions.put(newSession.id, newSession);
    517 
    518         return newSession;
    519     }
    520 
    521     /**
    522      * Asserts the component is owned by the caller.
    523      */
    524     private void assertCallerLocked(@NonNull ComponentName componentName, boolean compatMode) {
    525         final String packageName = componentName.getPackageName();
    526         final PackageManager pm = mContext.getPackageManager();
    527         final int callingUid = Binder.getCallingUid();
    528         final int packageUid;
    529         try {
    530             packageUid = pm.getPackageUidAsUser(packageName, UserHandle.getCallingUserId());
    531         } catch (NameNotFoundException e) {
    532             throw new SecurityException("Could not verify UID for " + componentName);
    533         }
    534         if (callingUid != packageUid && !LocalServices.getService(ActivityManagerInternal.class)
    535                 .hasRunningActivity(callingUid, packageName)) {
    536             final String[] packages = pm.getPackagesForUid(callingUid);
    537             final String callingPackage = packages != null ? packages[0] : "uid-" + callingUid;
    538             Slog.w(TAG, "App (package=" + callingPackage + ", UID=" + callingUid
    539                     + ") passed component (" + componentName + ") owned by UID " + packageUid);
    540 
    541             // NOTE: not using Helper.newLogMaker() because we don't have the session id
    542             final LogMaker log = new LogMaker(MetricsEvent.AUTOFILL_FORGED_COMPONENT_ATTEMPT)
    543                     .setPackageName(callingPackage)
    544                     .addTaggedData(MetricsEvent.FIELD_AUTOFILL_SERVICE, getServicePackageName())
    545                     .addTaggedData(MetricsEvent.FIELD_AUTOFILL_FORGED_COMPONENT_NAME,
    546                             componentName == null ? "null" : componentName.flattenToShortString());
    547             if (compatMode) {
    548                 log.addTaggedData(MetricsEvent.FIELD_AUTOFILL_COMPAT_MODE, 1);
    549             }
    550             mMetricsLogger.write(log);
    551 
    552             throw new SecurityException("Invalid component: " + componentName);
    553         }
    554     }
    555 
    556     /**
    557      * Restores a session after an activity was temporarily destroyed.
    558      *
    559      * @param sessionId The id of the session to restore
    560      * @param uid UID of the process that tries to restore the session
    561      * @param activityToken The new instance of the activity
    562      * @param appCallback The callbacks to the activity
    563      */
    564     boolean restoreSession(int sessionId, int uid, @NonNull IBinder activityToken,
    565             @NonNull IBinder appCallback) {
    566         final Session session = mSessions.get(sessionId);
    567 
    568         if (session == null || uid != session.uid) {
    569             return false;
    570         } else {
    571             session.switchActivity(activityToken, appCallback);
    572             return true;
    573         }
    574     }
    575 
    576     /**
    577      * Updates a session and returns whether it should be restarted.
    578      */
    579     @GuardedBy("mLock")
    580     boolean updateSessionLocked(int sessionId, int uid, AutofillId autofillId, Rect virtualBounds,
    581             AutofillValue value, int action, int flags) {
    582         final Session session = mSessions.get(sessionId);
    583         if (session == null || session.uid != uid) {
    584             if ((flags & FLAG_MANUAL_REQUEST) != 0) {
    585                 if (sDebug) {
    586                     Slog.d(TAG, "restarting session " + sessionId + " due to manual request on "
    587                             + autofillId);
    588                 }
    589                 return true;
    590             }
    591             if (sVerbose) {
    592                 Slog.v(TAG, "updateSessionLocked(): session gone for " + sessionId
    593                         + "(" + uid + ")");
    594             }
    595             return false;
    596         }
    597 
    598         session.updateLocked(autofillId, virtualBounds, value, action, flags);
    599         return false;
    600     }
    601 
    602     @GuardedBy("mLock")
    603     void removeSessionLocked(int sessionId) {
    604         mSessions.remove(sessionId);
    605     }
    606 
    607     void handleSessionSave(Session session) {
    608         synchronized (mLock) {
    609             if (mSessions.get(session.id) == null) {
    610                 Slog.w(TAG, "handleSessionSave(): already gone: " + session.id);
    611 
    612                 return;
    613             }
    614             session.callSaveLocked();
    615         }
    616     }
    617 
    618     void onPendingSaveUi(int operation, @NonNull IBinder token) {
    619         if (sVerbose) Slog.v(TAG, "onPendingSaveUi(" + operation + "): " + token);
    620         synchronized (mLock) {
    621             final int sessionCount = mSessions.size();
    622             for (int i = sessionCount - 1; i >= 0; i--) {
    623                 final Session session = mSessions.valueAt(i);
    624                 if (session.isSaveUiPendingForTokenLocked(token)) {
    625                     session.onPendingSaveUi(operation, token);
    626                     return;
    627                 }
    628             }
    629         }
    630         if (sDebug) {
    631             Slog.d(TAG, "No pending Save UI for token " + token + " and operation "
    632                     + DebugUtils.flagsToString(AutofillManager.class, "PENDING_UI_OPERATION_",
    633                             operation));
    634         }
    635     }
    636 
    637     @GuardedBy("mLock")
    638     void handlePackageUpdateLocked(String packageName) {
    639         final ServiceInfo serviceInfo = mFieldClassificationStrategy.getServiceInfo();
    640         if (serviceInfo != null && serviceInfo.packageName.equals(packageName)) {
    641             resetExtServiceLocked();
    642         }
    643     }
    644 
    645     @GuardedBy("mLock")
    646     void resetExtServiceLocked() {
    647         if (sVerbose) Slog.v(TAG, "reset autofill service.");
    648         mFieldClassificationStrategy.reset();
    649     }
    650 
    651     @GuardedBy("mLock")
    652     void destroyLocked() {
    653         if (sVerbose) Slog.v(TAG, "destroyLocked()");
    654 
    655         resetExtServiceLocked();
    656 
    657         final int numSessions = mSessions.size();
    658         final ArraySet<RemoteFillService> remoteFillServices = new ArraySet<>(numSessions);
    659         for (int i = 0; i < numSessions; i++) {
    660             final RemoteFillService remoteFillService = mSessions.valueAt(i).destroyLocked();
    661             if (remoteFillService != null) {
    662                 remoteFillServices.add(remoteFillService);
    663             }
    664         }
    665         mSessions.clear();
    666         for (int i = 0; i < remoteFillServices.size(); i++) {
    667             remoteFillServices.valueAt(i).destroy();
    668         }
    669 
    670         sendStateToClients(true);
    671         if (mClients != null) {
    672             mClients.kill();
    673             mClients = null;
    674         }
    675     }
    676 
    677     @NonNull
    678     CharSequence getServiceLabel() {
    679         final CharSequence label = mInfo.getServiceInfo().loadSafeLabel(
    680                 mContext.getPackageManager(), 0 /* do not ellipsize */,
    681                 PackageItemInfo.SAFE_LABEL_FLAG_FIRST_LINE | PackageItemInfo.SAFE_LABEL_FLAG_TRIM);
    682         return label;
    683     }
    684 
    685     @NonNull
    686     Drawable getServiceIcon() {
    687         return mInfo.getServiceInfo().loadIcon(mContext.getPackageManager());
    688     }
    689 
    690     /**
    691      * Initializes the last fill selection after an autofill service returned a new
    692      * {@link FillResponse}.
    693      */
    694     void setLastResponse(int sessionId, @NonNull FillResponse response) {
    695         synchronized (mLock) {
    696             mEventHistory = new FillEventHistory(sessionId, response.getClientState());
    697         }
    698     }
    699 
    700     /**
    701      * Resets the last fill selection.
    702      */
    703     void resetLastResponse() {
    704         synchronized (mLock) {
    705             mEventHistory = null;
    706         }
    707     }
    708 
    709     @GuardedBy("mLock")
    710     private boolean isValidEventLocked(String method, int sessionId) {
    711         if (mEventHistory == null) {
    712             Slog.w(TAG, method + ": not logging event because history is null");
    713             return false;
    714         }
    715         if (sessionId != mEventHistory.getSessionId()) {
    716             if (sDebug) {
    717                 Slog.d(TAG, method + ": not logging event for session " + sessionId
    718                         + " because tracked session is " + mEventHistory.getSessionId());
    719             }
    720             return false;
    721         }
    722         return true;
    723     }
    724 
    725     /**
    726      * Updates the last fill selection when an authentication was selected.
    727      */
    728     void setAuthenticationSelected(int sessionId, @Nullable Bundle clientState) {
    729         synchronized (mLock) {
    730             if (isValidEventLocked("setAuthenticationSelected()", sessionId)) {
    731                 mEventHistory.addEvent(
    732                         new Event(Event.TYPE_AUTHENTICATION_SELECTED, null, clientState, null, null,
    733                                 null, null, null, null, null, null));
    734             }
    735         }
    736     }
    737 
    738     /**
    739      * Updates the last fill selection when an dataset authentication was selected.
    740      */
    741     void logDatasetAuthenticationSelected(@Nullable String selectedDataset, int sessionId,
    742             @Nullable Bundle clientState) {
    743         synchronized (mLock) {
    744             if (isValidEventLocked("logDatasetAuthenticationSelected()", sessionId)) {
    745                 mEventHistory.addEvent(
    746                         new Event(Event.TYPE_DATASET_AUTHENTICATION_SELECTED, selectedDataset,
    747                                 clientState, null, null, null, null, null, null, null, null));
    748             }
    749         }
    750     }
    751 
    752     /**
    753      * Updates the last fill selection when an save Ui is shown.
    754      */
    755     void logSaveShown(int sessionId, @Nullable Bundle clientState) {
    756         synchronized (mLock) {
    757             if (isValidEventLocked("logSaveShown()", sessionId)) {
    758                 mEventHistory.addEvent(new Event(Event.TYPE_SAVE_SHOWN, null, clientState, null,
    759                         null, null, null, null, null, null, null));
    760             }
    761         }
    762     }
    763 
    764     /**
    765      * Updates the last fill response when a dataset was selected.
    766      */
    767     void logDatasetSelected(@Nullable String selectedDataset, int sessionId,
    768             @Nullable Bundle clientState) {
    769         synchronized (mLock) {
    770             if (isValidEventLocked("logDatasetSelected()", sessionId)) {
    771                 mEventHistory.addEvent(
    772                         new Event(Event.TYPE_DATASET_SELECTED, selectedDataset, clientState, null,
    773                                 null, null, null, null, null, null, null));
    774             }
    775         }
    776     }
    777 
    778     /**
    779      * Updates the last fill response when an autofill context is committed.
    780      */
    781     @GuardedBy("mLock")
    782     void logContextCommittedLocked(int sessionId, @Nullable Bundle clientState,
    783             @Nullable ArrayList<String> selectedDatasets,
    784             @Nullable ArraySet<String> ignoredDatasets,
    785             @Nullable ArrayList<AutofillId> changedFieldIds,
    786             @Nullable ArrayList<String> changedDatasetIds,
    787             @Nullable ArrayList<AutofillId> manuallyFilledFieldIds,
    788             @Nullable ArrayList<ArrayList<String>> manuallyFilledDatasetIds,
    789             @NonNull ComponentName appComponentName, boolean compatMode) {
    790         logContextCommittedLocked(sessionId, clientState, selectedDatasets, ignoredDatasets,
    791                 changedFieldIds, changedDatasetIds, manuallyFilledFieldIds,
    792                 manuallyFilledDatasetIds, null, null, appComponentName, compatMode);
    793     }
    794 
    795     @GuardedBy("mLock")
    796     void logContextCommittedLocked(int sessionId, @Nullable Bundle clientState,
    797             @Nullable ArrayList<String> selectedDatasets,
    798             @Nullable ArraySet<String> ignoredDatasets,
    799             @Nullable ArrayList<AutofillId> changedFieldIds,
    800             @Nullable ArrayList<String> changedDatasetIds,
    801             @Nullable ArrayList<AutofillId> manuallyFilledFieldIds,
    802             @Nullable ArrayList<ArrayList<String>> manuallyFilledDatasetIds,
    803             @Nullable ArrayList<AutofillId> detectedFieldIdsList,
    804             @Nullable ArrayList<FieldClassification> detectedFieldClassificationsList,
    805             @NonNull ComponentName appComponentName, boolean compatMode) {
    806         if (isValidEventLocked("logDatasetNotSelected()", sessionId)) {
    807             if (sVerbose) {
    808                 Slog.v(TAG, "logContextCommitted() with FieldClassification: id=" + sessionId
    809                         + ", selectedDatasets=" + selectedDatasets
    810                         + ", ignoredDatasetIds=" + ignoredDatasets
    811                         + ", changedAutofillIds=" + changedFieldIds
    812                         + ", changedDatasetIds=" + changedDatasetIds
    813                         + ", manuallyFilledFieldIds=" + manuallyFilledFieldIds
    814                         + ", detectedFieldIds=" + detectedFieldIdsList
    815                         + ", detectedFieldClassifications=" + detectedFieldClassificationsList
    816                         + ", appComponentName=" + appComponentName.toShortString()
    817                         + ", compatMode=" + compatMode);
    818             }
    819             AutofillId[] detectedFieldsIds = null;
    820             FieldClassification[] detectedFieldClassifications = null;
    821             if (detectedFieldIdsList != null) {
    822                 detectedFieldsIds = new AutofillId[detectedFieldIdsList.size()];
    823                 detectedFieldIdsList.toArray(detectedFieldsIds);
    824                 detectedFieldClassifications =
    825                         new FieldClassification[detectedFieldClassificationsList.size()];
    826                 detectedFieldClassificationsList.toArray(detectedFieldClassifications);
    827 
    828                 final int numberFields = detectedFieldsIds.length;
    829                 int totalSize = 0;
    830                 float totalScore = 0;
    831                 for (int i = 0; i < numberFields; i++) {
    832                     final FieldClassification fc = detectedFieldClassifications[i];
    833                     final List<Match> matches = fc.getMatches();
    834                     final int size = matches.size();
    835                     totalSize += size;
    836                     for (int j = 0; j < size; j++) {
    837                         totalScore += matches.get(j).getScore();
    838                     }
    839                 }
    840 
    841                 final int averageScore = (int) ((totalScore * 100) / totalSize);
    842                 mMetricsLogger.write(Helper
    843                         .newLogMaker(MetricsEvent.AUTOFILL_FIELD_CLASSIFICATION_MATCHES,
    844                                 appComponentName, getServicePackageName(), sessionId, compatMode)
    845                         .setCounterValue(numberFields)
    846                         .addTaggedData(MetricsEvent.FIELD_AUTOFILL_MATCH_SCORE,
    847                                 averageScore));
    848             }
    849             mEventHistory.addEvent(new Event(Event.TYPE_CONTEXT_COMMITTED, null,
    850                     clientState, selectedDatasets, ignoredDatasets,
    851                     changedFieldIds, changedDatasetIds,
    852                     manuallyFilledFieldIds, manuallyFilledDatasetIds,
    853                     detectedFieldsIds, detectedFieldClassifications));
    854         }
    855     }
    856 
    857     /**
    858      * Gets the fill event history.
    859      *
    860      * @param callingUid The calling uid
    861      *
    862      * @return The history or {@code null} if there is none.
    863      */
    864     FillEventHistory getFillEventHistory(int callingUid) {
    865         synchronized (mLock) {
    866             if (mEventHistory != null
    867                     && isCalledByServiceLocked("getFillEventHistory", callingUid)) {
    868                 return mEventHistory;
    869             }
    870         }
    871         return null;
    872     }
    873 
    874     // Called by Session - does not need to check uid
    875     UserData getUserData() {
    876         synchronized (mLock) {
    877             return mUserData;
    878         }
    879     }
    880 
    881     // Called by AutofillManager
    882     UserData getUserData(int callingUid) {
    883         synchronized (mLock) {
    884             if (isCalledByServiceLocked("getUserData", callingUid)) {
    885                 return mUserData;
    886             }
    887         }
    888         return null;
    889     }
    890 
    891     // Called by AutofillManager
    892     void setUserData(int callingUid, UserData userData) {
    893         synchronized (mLock) {
    894             if (!isCalledByServiceLocked("setUserData", callingUid)) {
    895                 return;
    896             }
    897             mUserData = userData;
    898             // Log it
    899             final int numberFields = mUserData == null ? 0: mUserData.getCategoryIds().length;
    900             // NOTE: contrary to most metrics, the service name is logged as the main package name
    901             // here, not as MetricsEvent.FIELD_AUTOFILL_SERVICE
    902             mMetricsLogger.write(new LogMaker(MetricsEvent.AUTOFILL_USERDATA_UPDATED)
    903                     .setPackageName(getServicePackageName())
    904                     .addTaggedData(MetricsEvent.FIELD_AUTOFILL_NUM_VALUES, numberFields));
    905         }
    906     }
    907 
    908     @GuardedBy("mLock")
    909     private boolean isCalledByServiceLocked(String methodName, int callingUid) {
    910         if (getServiceUidLocked() != callingUid) {
    911             Slog.w(TAG, methodName + "() called by UID " + callingUid
    912                     + ", but service UID is " + getServiceUidLocked());
    913             return false;
    914         }
    915         return true;
    916     }
    917 
    918     @GuardedBy("mLock")
    919     void dumpLocked(String prefix, PrintWriter pw) {
    920         final String prefix2 = prefix + "  ";
    921 
    922         pw.print(prefix); pw.print("User: "); pw.println(mUserId);
    923         pw.print(prefix); pw.print("UID: "); pw.println(getServiceUidLocked());
    924         pw.print(prefix); pw.print("Autofill Service Info: ");
    925         if (mInfo == null) {
    926             pw.println("N/A");
    927         } else {
    928             pw.println();
    929             mInfo.dump(prefix2, pw);
    930             pw.print(prefix); pw.print("Service Label: "); pw.println(getServiceLabel());
    931         }
    932         pw.print(prefix); pw.print("Component from settings: ");
    933             pw.println(getComponentNameFromSettings());
    934         pw.print(prefix); pw.print("Default component: ");
    935             pw.println(mContext.getString(R.string.config_defaultAutofillService));
    936         pw.print(prefix); pw.print("Disabled: "); pw.println(mDisabled);
    937         pw.print(prefix); pw.print("Field classification enabled: ");
    938             pw.println(isFieldClassificationEnabledLocked());
    939         pw.print(prefix); pw.print("Compat pkgs: ");
    940         final ArrayMap<String, Long> compatPkgs = getCompatibilityPackagesLocked();
    941         if (compatPkgs == null) {
    942             pw.println("N/A");
    943         } else {
    944             pw.println(compatPkgs);
    945         }
    946         pw.print(prefix); pw.print("Setup complete: "); pw.println(mSetupComplete);
    947         pw.print(prefix); pw.print("Last prune: "); pw.println(mLastPrune);
    948 
    949         pw.print(prefix); pw.print("Disabled apps: ");
    950 
    951         if (mDisabledApps == null) {
    952             pw.println("N/A");
    953         } else {
    954             final int size = mDisabledApps.size();
    955             pw.println(size);
    956             final StringBuilder builder = new StringBuilder();
    957             final long now = SystemClock.elapsedRealtime();
    958             for (int i = 0; i < size; i++) {
    959                 final String packageName = mDisabledApps.keyAt(i);
    960                 final long expiration = mDisabledApps.valueAt(i);
    961                  builder.append(prefix).append(prefix)
    962                      .append(i).append(". ").append(packageName).append(": ");
    963                  TimeUtils.formatDuration((expiration - now), builder);
    964                  builder.append('\n');
    965              }
    966              pw.println(builder);
    967         }
    968 
    969         pw.print(prefix); pw.print("Disabled activities: ");
    970 
    971         if (mDisabledActivities == null) {
    972             pw.println("N/A");
    973         } else {
    974             final int size = mDisabledActivities.size();
    975             pw.println(size);
    976             final StringBuilder builder = new StringBuilder();
    977             final long now = SystemClock.elapsedRealtime();
    978             for (int i = 0; i < size; i++) {
    979                 final ComponentName component = mDisabledActivities.keyAt(i);
    980                 final long expiration = mDisabledActivities.valueAt(i);
    981                  builder.append(prefix).append(prefix)
    982                      .append(i).append(". ").append(component).append(": ");
    983                  TimeUtils.formatDuration((expiration - now), builder);
    984                  builder.append('\n');
    985              }
    986              pw.println(builder);
    987         }
    988 
    989         final int size = mSessions.size();
    990         if (size == 0) {
    991             pw.print(prefix); pw.println("No sessions");
    992         } else {
    993             pw.print(prefix); pw.print(size); pw.println(" sessions:");
    994             for (int i = 0; i < size; i++) {
    995                 pw.print(prefix); pw.print("#"); pw.println(i + 1);
    996                 mSessions.valueAt(i).dumpLocked(prefix2, pw);
    997             }
    998         }
    999 
   1000         pw.print(prefix); pw.print("Clients: ");
   1001         if (mClients == null) {
   1002             pw.println("N/A");
   1003         } else {
   1004             pw.println();
   1005             mClients.dump(pw, prefix2);
   1006         }
   1007 
   1008         if (mEventHistory == null || mEventHistory.getEvents() == null
   1009                 || mEventHistory.getEvents().size() == 0) {
   1010             pw.print(prefix); pw.println("No event on last fill response");
   1011         } else {
   1012             pw.print(prefix); pw.println("Events of last fill response:");
   1013             pw.print(prefix);
   1014 
   1015             int numEvents = mEventHistory.getEvents().size();
   1016             for (int i = 0; i < numEvents; i++) {
   1017                 final Event event = mEventHistory.getEvents().get(i);
   1018                 pw.println("  " + i + ": eventType=" + event.getType() + " datasetId="
   1019                         + event.getDatasetId());
   1020             }
   1021         }
   1022 
   1023         pw.print(prefix); pw.print("User data: ");
   1024         if (mUserData == null) {
   1025             pw.println("N/A");
   1026         } else {
   1027             pw.println();
   1028             mUserData.dump(prefix2, pw);
   1029         }
   1030 
   1031         pw.print(prefix); pw.println("Field Classification strategy: ");
   1032         mFieldClassificationStrategy.dump(prefix2, pw);
   1033     }
   1034 
   1035     @GuardedBy("mLock")
   1036     void destroySessionsLocked() {
   1037         if (mSessions.size() == 0) {
   1038             mUi.destroyAll(null, null, false);
   1039             return;
   1040         }
   1041         while (mSessions.size() > 0) {
   1042             mSessions.valueAt(0).forceRemoveSelfLocked();
   1043         }
   1044     }
   1045 
   1046     // TODO(b/64940307): remove this method if SaveUI is refactored to be attached on activities
   1047     @GuardedBy("mLock")
   1048     void destroyFinishedSessionsLocked() {
   1049         final int sessionCount = mSessions.size();
   1050         for (int i = sessionCount - 1; i >= 0; i--) {
   1051             final Session session = mSessions.valueAt(i);
   1052             if (session.isSavingLocked()) {
   1053                 if (sDebug) Slog.d(TAG, "destroyFinishedSessionsLocked(): " + session.id);
   1054                 session.forceRemoveSelfLocked();
   1055             }
   1056         }
   1057     }
   1058 
   1059     @GuardedBy("mLock")
   1060     void listSessionsLocked(ArrayList<String> output) {
   1061         final int numSessions = mSessions.size();
   1062         for (int i = 0; i < numSessions; i++) {
   1063             output.add((mInfo != null ? mInfo.getServiceInfo().getComponentName()
   1064                     : null) + ":" + mSessions.keyAt(i));
   1065         }
   1066     }
   1067 
   1068     @GuardedBy("mLock")
   1069     @Nullable ArrayMap<String, Long> getCompatibilityPackagesLocked() {
   1070         if (mInfo != null) {
   1071             return mInfo.getCompatibilityPackages();
   1072         }
   1073         return null;
   1074     }
   1075 
   1076     private void sendStateToClients(boolean resetClient) {
   1077         final RemoteCallbackList<IAutoFillManagerClient> clients;
   1078         final int userClientCount;
   1079         synchronized (mLock) {
   1080             if (mClients == null) {
   1081                 return;
   1082             }
   1083             clients = mClients;
   1084             userClientCount = clients.beginBroadcast();
   1085         }
   1086         try {
   1087             for (int i = 0; i < userClientCount; i++) {
   1088                 final IAutoFillManagerClient client = clients.getBroadcastItem(i);
   1089                 try {
   1090                     final boolean resetSession;
   1091                     final boolean isEnabled;
   1092                     synchronized (mLock) {
   1093                         resetSession = resetClient || isClientSessionDestroyedLocked(client);
   1094                         isEnabled = isEnabledLocked();
   1095                     }
   1096                     int flags = 0;
   1097                     if (isEnabled) {
   1098                         flags |= AutofillManager.SET_STATE_FLAG_ENABLED;
   1099                     }
   1100                     if (resetSession) {
   1101                         flags |= AutofillManager.SET_STATE_FLAG_RESET_SESSION;
   1102                     }
   1103                     if (resetClient) {
   1104                         flags |= AutofillManager.SET_STATE_FLAG_RESET_CLIENT;
   1105                     }
   1106                     if (sDebug) {
   1107                         flags |= AutofillManager.SET_STATE_FLAG_DEBUG;
   1108                     }
   1109                     if (sVerbose) {
   1110                         flags |= AutofillManager.SET_STATE_FLAG_VERBOSE;
   1111                     }
   1112                     client.setState(flags);
   1113                 } catch (RemoteException re) {
   1114                     /* ignore */
   1115                 }
   1116             }
   1117         } finally {
   1118             clients.finishBroadcast();
   1119         }
   1120     }
   1121 
   1122     @GuardedBy("mLock")
   1123     private boolean isClientSessionDestroyedLocked(IAutoFillManagerClient client) {
   1124         final int sessionCount = mSessions.size();
   1125         for (int i = 0; i < sessionCount; i++) {
   1126             final Session session = mSessions.valueAt(i);
   1127             if (session.getClient().equals(client)) {
   1128                 return session.isDestroyed();
   1129             }
   1130         }
   1131         return true;
   1132     }
   1133 
   1134     @GuardedBy("mLock")
   1135     boolean isEnabledLocked() {
   1136         return mSetupComplete && mInfo != null && !mDisabled;
   1137     }
   1138 
   1139     /**
   1140      * Called by {@link Session} when service asked to disable autofill for an app.
   1141      */
   1142     void disableAutofillForApp(@NonNull String packageName, long duration, int sessionId,
   1143             boolean compatMode) {
   1144         synchronized (mLock) {
   1145             if (mDisabledApps == null) {
   1146                 mDisabledApps = new ArrayMap<>(1);
   1147             }
   1148             long expiration = SystemClock.elapsedRealtime() + duration;
   1149             // Protect it against overflow
   1150             if (expiration < 0) {
   1151                 expiration = Long.MAX_VALUE;
   1152             }
   1153             mDisabledApps.put(packageName, expiration);
   1154             int intDuration = duration > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) duration;
   1155             mMetricsLogger.write(Helper.newLogMaker(MetricsEvent.AUTOFILL_SERVICE_DISABLED_APP,
   1156                     packageName, getServicePackageName(), sessionId, compatMode)
   1157                     .addTaggedData(MetricsEvent.FIELD_AUTOFILL_DURATION, intDuration));
   1158         }
   1159     }
   1160 
   1161     /**
   1162      * Called by {@link Session} when service asked to disable autofill an app.
   1163      */
   1164     void disableAutofillForActivity(@NonNull ComponentName componentName, long duration,
   1165             int sessionId, boolean compatMode) {
   1166         synchronized (mLock) {
   1167             if (mDisabledActivities == null) {
   1168                 mDisabledActivities = new ArrayMap<>(1);
   1169             }
   1170             long expiration = SystemClock.elapsedRealtime() + duration;
   1171             // Protect it against overflow
   1172             if (expiration < 0) {
   1173                 expiration = Long.MAX_VALUE;
   1174             }
   1175             mDisabledActivities.put(componentName, expiration);
   1176             final int intDuration = duration > Integer.MAX_VALUE
   1177                     ? Integer.MAX_VALUE
   1178                     : (int) duration;
   1179             // NOTE: not using Helper.newLogMaker() because we're setting the componentName instead
   1180             // of package name
   1181             final LogMaker log = new LogMaker(MetricsEvent.AUTOFILL_SERVICE_DISABLED_ACTIVITY)
   1182                     .setComponentName(componentName)
   1183                     .addTaggedData(MetricsEvent.FIELD_AUTOFILL_SERVICE, getServicePackageName())
   1184                     .addTaggedData(MetricsEvent.FIELD_AUTOFILL_DURATION, intDuration)
   1185                     .addTaggedData(MetricsEvent.FIELD_AUTOFILL_SESSION_ID, sessionId);
   1186             if (compatMode) {
   1187                 log.addTaggedData(MetricsEvent.FIELD_AUTOFILL_COMPAT_MODE, 1);
   1188             }
   1189             mMetricsLogger.write(log);
   1190         }
   1191     }
   1192 
   1193     /**
   1194      * Checks if autofill is disabled by service to the given activity.
   1195      */
   1196     @GuardedBy("mLock")
   1197     private boolean isAutofillDisabledLocked(@NonNull ComponentName componentName) {
   1198         // Check activities first.
   1199         long elapsedTime = 0;
   1200         if (mDisabledActivities != null) {
   1201             elapsedTime = SystemClock.elapsedRealtime();
   1202             final Long expiration = mDisabledActivities.get(componentName);
   1203             if (expiration != null) {
   1204                 if (expiration >= elapsedTime) return true;
   1205                 // Restriction expired - clean it up.
   1206                 if (sVerbose) {
   1207                     Slog.v(TAG, "Removing " + componentName.toShortString()
   1208                         + " from disabled list");
   1209                 }
   1210                 mDisabledActivities.remove(componentName);
   1211             }
   1212         }
   1213 
   1214         // Then check apps.
   1215         final String packageName = componentName.getPackageName();
   1216         if (mDisabledApps == null) return false;
   1217 
   1218         final Long expiration = mDisabledApps.get(packageName);
   1219         if (expiration == null) return false;
   1220 
   1221         if (elapsedTime == 0) {
   1222             elapsedTime = SystemClock.elapsedRealtime();
   1223         }
   1224 
   1225         if (expiration >= elapsedTime) return true;
   1226 
   1227         // Restriction expired - clean it up.
   1228         if (sVerbose)  Slog.v(TAG, "Removing " + packageName + " from disabled list");
   1229         mDisabledApps.remove(packageName);
   1230         return false;
   1231     }
   1232 
   1233     // Called by AutofillManager, checks UID.
   1234     boolean isFieldClassificationEnabled(int callingUid) {
   1235         synchronized (mLock) {
   1236             if (!isCalledByServiceLocked("isFieldClassificationEnabled", callingUid)) {
   1237                 return false;
   1238             }
   1239             return isFieldClassificationEnabledLocked();
   1240         }
   1241     }
   1242 
   1243     // Called by internally, no need to check UID.
   1244     boolean isFieldClassificationEnabledLocked() {
   1245         return Settings.Secure.getIntForUser(
   1246                 mContext.getContentResolver(),
   1247                 Settings.Secure.AUTOFILL_FEATURE_FIELD_CLASSIFICATION, 1,
   1248                 mUserId) == 1;
   1249     }
   1250 
   1251     FieldClassificationStrategy getFieldClassificationStrategy() {
   1252         return mFieldClassificationStrategy;
   1253     }
   1254 
   1255     String[] getAvailableFieldClassificationAlgorithms(int callingUid) {
   1256         synchronized (mLock) {
   1257             if (!isCalledByServiceLocked("getFCAlgorithms()", callingUid)) {
   1258                 return null;
   1259             }
   1260         }
   1261         return mFieldClassificationStrategy.getAvailableAlgorithms();
   1262     }
   1263 
   1264     String getDefaultFieldClassificationAlgorithm(int callingUid) {
   1265         synchronized (mLock) {
   1266             if (!isCalledByServiceLocked("getDefaultFCAlgorithm()", callingUid)) {
   1267                 return null;
   1268             }
   1269         }
   1270         return mFieldClassificationStrategy.getDefaultAlgorithm();
   1271     }
   1272 
   1273     @Override
   1274     public String toString() {
   1275         return "AutofillManagerServiceImpl: [userId=" + mUserId
   1276                 + ", component=" + (mInfo != null
   1277                 ? mInfo.getServiceInfo().getComponentName() : null) + "]";
   1278     }
   1279 
   1280     /** Task used to prune abandoned session */
   1281     private class PruneTask extends AsyncTask<Void, Void, Void> {
   1282         @Override
   1283         protected Void doInBackground(Void... ignored) {
   1284             int numSessionsToRemove;
   1285 
   1286             SparseArray<IBinder> sessionsToRemove;
   1287 
   1288             synchronized (mLock) {
   1289                 numSessionsToRemove = mSessions.size();
   1290                 sessionsToRemove = new SparseArray<>(numSessionsToRemove);
   1291 
   1292                 for (int i = 0; i < numSessionsToRemove; i++) {
   1293                     Session session = mSessions.valueAt(i);
   1294 
   1295                     sessionsToRemove.put(session.id, session.getActivityTokenLocked());
   1296                 }
   1297             }
   1298 
   1299             IActivityManager am = ActivityManager.getService();
   1300 
   1301             // Only remove sessions which's activities are not known to the activity manager anymore
   1302             for (int i = 0; i < numSessionsToRemove; i++) {
   1303                 try {
   1304                     // The activity manager cannot resolve activities that have been removed
   1305                     if (am.getActivityClassForToken(sessionsToRemove.valueAt(i)) != null) {
   1306                         sessionsToRemove.removeAt(i);
   1307                         i--;
   1308                         numSessionsToRemove--;
   1309                     }
   1310                 } catch (RemoteException e) {
   1311                     Slog.w(TAG, "Cannot figure out if activity is finished", e);
   1312                 }
   1313             }
   1314 
   1315             synchronized (mLock) {
   1316                 for (int i = 0; i < numSessionsToRemove; i++) {
   1317                     Session sessionToRemove = mSessions.get(sessionsToRemove.keyAt(i));
   1318 
   1319                     if (sessionToRemove != null && sessionsToRemove.valueAt(i)
   1320                             == sessionToRemove.getActivityTokenLocked()) {
   1321                         if (sessionToRemove.isSavingLocked()) {
   1322                             if (sVerbose) {
   1323                                 Slog.v(TAG, "Session " + sessionToRemove.id + " is saving");
   1324                             }
   1325                         } else {
   1326                             if (sDebug) {
   1327                                 Slog.i(TAG, "Prune session " + sessionToRemove.id + " ("
   1328                                     + sessionToRemove.getActivityTokenLocked() + ")");
   1329                             }
   1330                             sessionToRemove.removeSelfLocked();
   1331                         }
   1332                     }
   1333                 }
   1334             }
   1335 
   1336             return null;
   1337         }
   1338     }
   1339 }
   1340