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