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