AutofillManagerServiceImpl.java revision 6eb77633d9fc8996f44b36e11a722e3b729c7588
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 17package com.android.server.autofill; 18 19import static android.service.autofill.FillRequest.FLAG_MANUAL_REQUEST; 20import static android.view.autofill.AutofillManager.ACTION_START_SESSION; 21import static android.view.autofill.AutofillManager.NO_SESSION; 22 23import static com.android.server.autofill.Helper.sDebug; 24import static com.android.server.autofill.Helper.sVerbose; 25 26import android.annotation.NonNull; 27import android.annotation.Nullable; 28import android.app.ActivityManager; 29import android.app.AppGlobals; 30import android.app.IActivityManager; 31import android.content.ComponentName; 32import android.content.Context; 33import android.content.pm.ApplicationInfo; 34import android.content.pm.PackageManager; 35import android.content.pm.PackageManager.NameNotFoundException; 36import android.content.pm.ServiceInfo; 37import android.graphics.Rect; 38import android.graphics.drawable.Drawable; 39import android.metrics.LogMaker; 40import android.os.AsyncTask; 41import android.os.Binder; 42import android.os.Bundle; 43import android.os.IBinder; 44import android.os.Looper; 45import android.os.RemoteCallbackList; 46import android.os.RemoteException; 47import android.os.UserHandle; 48import android.os.UserManager; 49import android.provider.Settings; 50import android.service.autofill.AutofillService; 51import android.service.autofill.AutofillServiceInfo; 52import android.service.autofill.FillEventHistory; 53import android.service.autofill.FillEventHistory.Event; 54import android.service.autofill.FillResponse; 55import android.service.autofill.IAutoFillService; 56import android.text.TextUtils; 57import android.util.ArraySet; 58import android.util.DebugUtils; 59import android.util.LocalLog; 60import android.util.Slog; 61import android.util.SparseArray; 62import android.view.autofill.AutofillId; 63import android.view.autofill.AutofillManager; 64import android.view.autofill.AutofillValue; 65import android.view.autofill.IAutoFillManagerClient; 66 67import com.android.internal.R; 68import com.android.internal.annotations.GuardedBy; 69import com.android.internal.logging.MetricsLogger; 70import com.android.internal.logging.nano.MetricsProto.MetricsEvent; 71import com.android.internal.os.HandlerCaller; 72import com.android.server.autofill.ui.AutoFillUI; 73 74import java.io.PrintWriter; 75import java.util.ArrayList; 76import java.util.Random; 77 78/** 79 * Bridge between the {@code system_server}'s {@link AutofillManagerService} and the 80 * app's {@link IAutoFillService} implementation. 81 * 82 */ 83final class AutofillManagerServiceImpl { 84 85 private static final String TAG = "AutofillManagerServiceImpl"; 86 private static final int MAX_SESSION_ID_CREATE_TRIES = 2048; 87 88 /** Minimum interval to prune abandoned sessions */ 89 private static final int MAX_ABANDONED_SESSION_MILLIS = 30000; 90 91 static final int MSG_SERVICE_SAVE = 1; 92 93 private final int mUserId; 94 private final Context mContext; 95 private final Object mLock; 96 private final AutoFillUI mUi; 97 private final MetricsLogger mMetricsLogger = new MetricsLogger(); 98 99 private RemoteCallbackList<IAutoFillManagerClient> mClients; 100 private AutofillServiceInfo mInfo; 101 102 private static final Random sRandom = new Random(); 103 104 private final LocalLog mRequestsHistory; 105 private final LocalLog mUiLatencyHistory; 106 107 /** 108 * Whether service was disabled for user due to {@link UserManager} restrictions. 109 */ 110 private boolean mDisabled; 111 112 /** 113 * Caches whether the setup completed for the current user. 114 */ 115 @GuardedBy("mLock") 116 private boolean mSetupComplete; 117 118 private final HandlerCaller.Callback mHandlerCallback = (msg) -> { 119 switch (msg.what) { 120 case MSG_SERVICE_SAVE: 121 handleSessionSave(msg.arg1); 122 break; 123 default: 124 Slog.w(TAG, "invalid msg on handler: " + msg); 125 } 126 }; 127 128 private final HandlerCaller mHandlerCaller = new HandlerCaller(null, Looper.getMainLooper(), 129 mHandlerCallback, true); 130 131 /** 132 * Cache of pending {@link Session}s, keyed by sessionId. 133 * 134 * <p>They're kept until the {@link AutofillService} finished handling a request, an error 135 * occurs, or the session is abandoned. 136 */ 137 @GuardedBy("mLock") 138 private final SparseArray<Session> mSessions = new SparseArray<>(); 139 140 /** The last selection */ 141 @GuardedBy("mLock") 142 private FillEventHistory mEventHistory; 143 144 /** When was {@link PruneTask} last executed? */ 145 private long mLastPrune = 0; 146 147 AutofillManagerServiceImpl(Context context, Object lock, LocalLog requestsHistory, 148 LocalLog uiLatencyHistory, int userId, AutoFillUI ui, boolean disabled) { 149 mContext = context; 150 mLock = lock; 151 mRequestsHistory = requestsHistory; 152 mUiLatencyHistory = uiLatencyHistory; 153 mUserId = userId; 154 mUi = ui; 155 updateLocked(disabled); 156 } 157 158 @Nullable 159 CharSequence getServiceName() { 160 final String packageName = getServicePackageName(); 161 if (packageName == null) { 162 return null; 163 } 164 165 try { 166 final PackageManager pm = mContext.getPackageManager(); 167 final ApplicationInfo info = pm.getApplicationInfo(packageName, 0); 168 return pm.getApplicationLabel(info); 169 } catch (Exception e) { 170 Slog.e(TAG, "Could not get label for " + packageName + ": " + e); 171 return packageName; 172 } 173 } 174 175 @Nullable 176 String getServicePackageName() { 177 final ComponentName serviceComponent = getServiceComponentName(); 178 if (serviceComponent != null) { 179 return serviceComponent.getPackageName(); 180 } 181 return null; 182 } 183 184 ComponentName getServiceComponentName() { 185 synchronized (mLock) { 186 if (mInfo == null) { 187 return null; 188 } 189 return mInfo.getServiceInfo().getComponentName(); 190 } 191 } 192 193 private boolean isSetupCompletedLocked() { 194 final String setupComplete = Settings.Secure.getStringForUser( 195 mContext.getContentResolver(), Settings.Secure.USER_SETUP_COMPLETE, mUserId); 196 return "1".equals(setupComplete); 197 } 198 199 private String getComponentNameFromSettings() { 200 return Settings.Secure.getStringForUser( 201 mContext.getContentResolver(), Settings.Secure.AUTOFILL_SERVICE, mUserId); 202 } 203 204 void updateLocked(boolean disabled) { 205 final boolean wasEnabled = isEnabled(); 206 if (sVerbose) { 207 Slog.v(TAG, "updateLocked(u=" + mUserId + "): wasEnabled=" + wasEnabled 208 + ", mSetupComplete= " + mSetupComplete 209 + ", disabled=" + disabled + ", mDisabled=" + mDisabled); 210 } 211 mSetupComplete = isSetupCompletedLocked(); 212 mDisabled = disabled; 213 ComponentName serviceComponent = null; 214 ServiceInfo serviceInfo = null; 215 final String componentName = getComponentNameFromSettings(); 216 if (!TextUtils.isEmpty(componentName)) { 217 try { 218 serviceComponent = ComponentName.unflattenFromString(componentName); 219 serviceInfo = AppGlobals.getPackageManager().getServiceInfo(serviceComponent, 220 0, mUserId); 221 } catch (RuntimeException | RemoteException e) { 222 Slog.e(TAG, "Bad autofill service name " + componentName + ": " + e); 223 return; 224 } 225 } 226 try { 227 if (serviceInfo != null) { 228 mInfo = new AutofillServiceInfo(mContext.getPackageManager(), 229 serviceComponent, mUserId); 230 if (sDebug) Slog.d(TAG, "Set component for user " + mUserId + " as " + mInfo); 231 } else { 232 mInfo = null; 233 if (sDebug) Slog.d(TAG, "Reset component for user " + mUserId); 234 } 235 final boolean isEnabled = isEnabled(); 236 if (wasEnabled != isEnabled) { 237 if (!isEnabled) { 238 final int sessionCount = mSessions.size(); 239 for (int i = sessionCount - 1; i >= 0; i--) { 240 final Session session = mSessions.valueAt(i); 241 session.removeSelfLocked(); 242 } 243 } 244 sendStateToClients(false); 245 } 246 } catch (Exception e) { 247 Slog.e(TAG, "Bad AutofillService '" + componentName + "': " + e); 248 } 249 } 250 251 boolean addClientLocked(IAutoFillManagerClient client) { 252 if (mClients == null) { 253 mClients = new RemoteCallbackList<>(); 254 } 255 mClients.register(client); 256 return isEnabled(); 257 } 258 259 void setAuthenticationResultLocked(Bundle data, int sessionId, int authenticationId, int uid) { 260 if (!isEnabled()) { 261 return; 262 } 263 final Session session = mSessions.get(sessionId); 264 if (session != null && uid == session.uid) { 265 session.setAuthenticationResultLocked(data, authenticationId); 266 } 267 } 268 269 void setHasCallback(int sessionId, int uid, boolean hasIt) { 270 if (!isEnabled()) { 271 return; 272 } 273 final Session session = mSessions.get(sessionId); 274 if (session != null && uid == session.uid) { 275 synchronized (mLock) { 276 session.setHasCallbackLocked(hasIt); 277 } 278 } 279 } 280 281 int startSessionLocked(@NonNull IBinder activityToken, int uid, 282 @NonNull IBinder appCallbackToken, @NonNull AutofillId autofillId, 283 @NonNull Rect virtualBounds, @Nullable AutofillValue value, boolean hasCallback, 284 int flags, @NonNull ComponentName componentName) { 285 if (!isEnabled()) { 286 return 0; 287 } 288 if (sVerbose) Slog.v(TAG, "startSession(): token=" + activityToken + ", flags=" + flags); 289 290 // Occasionally clean up abandoned sessions 291 pruneAbandonedSessionsLocked(); 292 293 final Session newSession = createSessionByTokenLocked(activityToken, uid, appCallbackToken, 294 hasCallback, componentName); 295 if (newSession == null) { 296 return NO_SESSION; 297 } 298 299 final String historyItem = 300 "id=" + newSession.id + " uid=" + uid + " s=" + mInfo.getServiceInfo().packageName 301 + " u=" + mUserId + " i=" + autofillId + " b=" + virtualBounds + " hc=" + 302 hasCallback + " f=" + flags; 303 mRequestsHistory.log(historyItem); 304 305 newSession.updateLocked(autofillId, virtualBounds, value, ACTION_START_SESSION, flags); 306 307 return newSession.id; 308 } 309 310 /** 311 * Remove abandoned sessions if needed. 312 */ 313 private void pruneAbandonedSessionsLocked() { 314 long now = System.currentTimeMillis(); 315 if (mLastPrune < now - MAX_ABANDONED_SESSION_MILLIS) { 316 mLastPrune = now; 317 318 if (mSessions.size() > 0) { 319 (new PruneTask()).execute(); 320 } 321 } 322 } 323 324 void finishSessionLocked(int sessionId, int uid) { 325 if (!isEnabled()) { 326 return; 327 } 328 329 final Session session = mSessions.get(sessionId); 330 if (session == null || uid != session.uid) { 331 if (sVerbose) { 332 Slog.v(TAG, "finishSessionLocked(): no session for " + sessionId + "(" + uid + ")"); 333 } 334 return; 335 } 336 337 final boolean finished = session.showSaveLocked(); 338 if (sVerbose) Slog.v(TAG, "finishSessionLocked(): session finished on save? " + finished); 339 340 if (finished) { 341 session.removeSelfLocked(); 342 } 343 } 344 345 void cancelSessionLocked(int sessionId, int uid) { 346 if (!isEnabled()) { 347 return; 348 } 349 350 final Session session = mSessions.get(sessionId); 351 if (session == null || uid != session.uid) { 352 Slog.w(TAG, "cancelSessionLocked(): no session for " + sessionId + "(" + uid + ")"); 353 return; 354 } 355 session.removeSelfLocked(); 356 } 357 358 void disableOwnedAutofillServicesLocked(int uid) { 359 Slog.i(TAG, "disableOwnedServices(" + uid + "): " + mInfo); 360 if (mInfo == null) return; 361 362 final ServiceInfo serviceInfo = mInfo.getServiceInfo(); 363 if (serviceInfo.applicationInfo.uid != uid) { 364 Slog.w(TAG, "disableOwnedServices(): ignored when called by UID " + uid 365 + " instead of " + serviceInfo.applicationInfo.uid 366 + " for service " + mInfo); 367 return; 368 } 369 370 371 final long identity = Binder.clearCallingIdentity(); 372 try { 373 final String autoFillService = getComponentNameFromSettings(); 374 final ComponentName componentName = serviceInfo.getComponentName(); 375 if (componentName.equals(ComponentName.unflattenFromString(autoFillService))) { 376 mMetricsLogger.action(MetricsEvent.AUTOFILL_SERVICE_DISABLED_SELF, 377 componentName.getPackageName()); 378 Settings.Secure.putStringForUser(mContext.getContentResolver(), 379 Settings.Secure.AUTOFILL_SERVICE, null, mUserId); 380 destroySessionsLocked(); 381 } else { 382 Slog.w(TAG, "disableOwnedServices(): ignored because current service (" 383 + serviceInfo + ") does not match Settings (" + autoFillService + ")"); 384 } 385 } finally { 386 Binder.restoreCallingIdentity(identity); 387 } 388 } 389 390 private Session createSessionByTokenLocked(@NonNull IBinder activityToken, int uid, 391 @NonNull IBinder appCallbackToken, boolean hasCallback, 392 @NonNull ComponentName componentName) { 393 // use random ids so that one app cannot know that another app creates sessions 394 int sessionId; 395 int tries = 0; 396 do { 397 tries++; 398 if (tries > MAX_SESSION_ID_CREATE_TRIES) { 399 Slog.w(TAG, "Cannot create session in " + MAX_SESSION_ID_CREATE_TRIES + " tries"); 400 return null; 401 } 402 403 sessionId = sRandom.nextInt(); 404 } while (sessionId == NO_SESSION || mSessions.indexOfKey(sessionId) >= 0); 405 406 assertCallerLocked(componentName); 407 408 final Session newSession = new Session(this, mUi, mContext, mHandlerCaller, mUserId, mLock, 409 sessionId, uid, activityToken, appCallbackToken, hasCallback, 410 mUiLatencyHistory, mInfo.getServiceInfo().getComponentName(), componentName); 411 mSessions.put(newSession.id, newSession); 412 413 return newSession; 414 } 415 416 /** 417 * Asserts the component is owned by the caller. 418 */ 419 private void assertCallerLocked(@NonNull ComponentName componentName) { 420 final PackageManager pm = mContext.getPackageManager(); 421 final int callingUid = Binder.getCallingUid(); 422 final int packageUid; 423 try { 424 packageUid = pm.getPackageUidAsUser(componentName.getPackageName(), 425 UserHandle.getCallingUserId()); 426 } catch (NameNotFoundException e) { 427 throw new SecurityException("Could not verify UID for " + componentName); 428 } 429 if (callingUid != packageUid) { 430 final String[] packages = pm.getPackagesForUid(callingUid); 431 final String callingPackage = packages != null ? packages[0] : "uid-" + callingUid; 432 Slog.w(TAG, "App (package=" + callingPackage + ", UID=" + callingUid 433 + ") passed component (" + componentName + ") owned by UID " + packageUid); 434 mMetricsLogger.write(new LogMaker(MetricsEvent.AUTOFILL_FORGED_COMPONENT_ATTEMPT) 435 .setPackageName(callingPackage) 436 .addTaggedData(MetricsEvent.FIELD_AUTOFILL_SERVICE, getServicePackageName()) 437 .addTaggedData(MetricsEvent.FIELD_AUTOFILL_FORGED_COMPONENT_NAME, 438 componentName == null ? "null" : componentName.flattenToShortString())); 439 throw new SecurityException("Invalid component: " + componentName); 440 } 441 } 442 443 /** 444 * Restores a session after an activity was temporarily destroyed. 445 * 446 * @param sessionId The id of the session to restore 447 * @param uid UID of the process that tries to restore the session 448 * @param activityToken The new instance of the activity 449 * @param appCallback The callbacks to the activity 450 */ 451 boolean restoreSession(int sessionId, int uid, @NonNull IBinder activityToken, 452 @NonNull IBinder appCallback) { 453 final Session session = mSessions.get(sessionId); 454 455 if (session == null || uid != session.uid) { 456 return false; 457 } else { 458 session.switchActivity(activityToken, appCallback); 459 return true; 460 } 461 } 462 463 /** 464 * Updates a session and returns whether it should be restarted. 465 */ 466 boolean updateSessionLocked(int sessionId, int uid, AutofillId autofillId, Rect virtualBounds, 467 AutofillValue value, int action, int flags) { 468 final Session session = mSessions.get(sessionId); 469 if (session == null || session.uid != uid) { 470 if ((flags & FLAG_MANUAL_REQUEST) != 0) { 471 if (sDebug) { 472 Slog.d(TAG, "restarting session " + sessionId + " due to manual request on " 473 + autofillId); 474 } 475 return true; 476 } 477 if (sVerbose) { 478 Slog.v(TAG, "updateSessionLocked(): session gone for " + sessionId 479 + "(" + uid + ")"); 480 } 481 return false; 482 } 483 484 session.updateLocked(autofillId, virtualBounds, value, action, flags); 485 return false; 486 } 487 488 void removeSessionLocked(int sessionId) { 489 mSessions.remove(sessionId); 490 } 491 492 private void handleSessionSave(int sessionId) { 493 synchronized (mLock) { 494 final Session session = mSessions.get(sessionId); 495 if (session == null) { 496 Slog.w(TAG, "handleSessionSave(): already gone: " + sessionId); 497 498 return; 499 } 500 session.callSaveLocked(); 501 } 502 } 503 504 void onPendingSaveUi(int operation, @NonNull IBinder token) { 505 if (sVerbose) Slog.v(TAG, "onPendingSaveUi(" + operation + "): " + token); 506 synchronized (mLock) { 507 final int sessionCount = mSessions.size(); 508 for (int i = sessionCount - 1; i >= 0; i--) { 509 final Session session = mSessions.valueAt(i); 510 if (session.isSaveUiPendingForTokenLocked(token)) { 511 session.onPendingSaveUi(operation, token); 512 return; 513 } 514 } 515 } 516 if (sDebug) { 517 Slog.d(TAG, "No pending Save UI for token " + token + " and operation " 518 + DebugUtils.flagsToString(AutofillManager.class, "PENDING_UI_OPERATION_", 519 operation)); 520 } 521 } 522 523 void destroyLocked() { 524 if (sVerbose) Slog.v(TAG, "destroyLocked()"); 525 526 final int numSessions = mSessions.size(); 527 final ArraySet<RemoteFillService> remoteFillServices = new ArraySet<>(numSessions); 528 for (int i = 0; i < numSessions; i++) { 529 final RemoteFillService remoteFillService = mSessions.valueAt(i).destroyLocked(); 530 if (remoteFillService != null) { 531 remoteFillServices.add(remoteFillService); 532 } 533 } 534 mSessions.clear(); 535 for (int i = 0; i < remoteFillServices.size(); i++) { 536 remoteFillServices.valueAt(i).destroy(); 537 } 538 539 sendStateToClients(true); 540 } 541 542 @NonNull 543 CharSequence getServiceLabel() { 544 return mInfo.getServiceInfo().loadLabel(mContext.getPackageManager()); 545 } 546 547 @NonNull 548 Drawable getServiceIcon() { 549 return mInfo.getServiceInfo().loadIcon(mContext.getPackageManager()); 550 } 551 552 /** 553 * Initializes the last fill selection after an autofill service returned a new 554 * {@link FillResponse}. 555 */ 556 void setLastResponse(int serviceUid, int sessionId, @NonNull FillResponse response) { 557 synchronized (mLock) { 558 mEventHistory = new FillEventHistory(serviceUid, sessionId, response.getClientState()); 559 } 560 } 561 562 /** 563 * Resets the last fill selection. 564 */ 565 void resetLastResponse() { 566 synchronized (mLock) { 567 mEventHistory = null; 568 } 569 } 570 571 private boolean isValidEventLocked(String method, int sessionId) { 572 if (mEventHistory == null) { 573 Slog.w(TAG, method + ": not logging event because history is null"); 574 return false; 575 } 576 if (sessionId != mEventHistory.getSessionId()) { 577 if (sDebug) { 578 Slog.d(TAG, method + ": not logging event for session " + sessionId 579 + " because tracked session is " + mEventHistory.getSessionId()); 580 } 581 return false; 582 } 583 return true; 584 } 585 586 /** 587 * Updates the last fill selection when an authentication was selected. 588 */ 589 void setAuthenticationSelected(int sessionId) { 590 synchronized (mLock) { 591 if (isValidEventLocked("setAuthenticationSelected()", sessionId)) { 592 mEventHistory.addEvent(new Event(Event.TYPE_AUTHENTICATION_SELECTED, null)); 593 } 594 } 595 } 596 597 /** 598 * Updates the last fill selection when an dataset authentication was selected. 599 */ 600 void logDatasetAuthenticationSelected(@Nullable String selectedDataset, int sessionId) { 601 synchronized (mLock) { 602 if (isValidEventLocked("logDatasetAuthenticationSelected()", sessionId)) { 603 mEventHistory.addEvent( 604 new Event(Event.TYPE_DATASET_AUTHENTICATION_SELECTED, selectedDataset)); 605 } 606 } 607 } 608 609 /** 610 * Updates the last fill selection when an save Ui is shown. 611 */ 612 void logSaveShown(int sessionId) { 613 synchronized (mLock) { 614 if (isValidEventLocked("logSaveShown()", sessionId)) { 615 mEventHistory.addEvent(new Event(Event.TYPE_SAVE_SHOWN, null)); 616 } 617 } 618 } 619 620 /** 621 * Updates the last fill response when a dataset was selected. 622 */ 623 void logDatasetSelected(@Nullable String selectedDataset, int sessionId) { 624 synchronized (mLock) { 625 if (isValidEventLocked("setDatasetSelected()", sessionId)) { 626 mEventHistory.addEvent(new Event(Event.TYPE_DATASET_SELECTED, selectedDataset)); 627 } 628 } 629 } 630 631 /** 632 * Gets the fill event history. 633 * 634 * @param callingUid The calling uid 635 * 636 * @return The history or {@code null} if there is none. 637 */ 638 FillEventHistory getFillEventHistory(int callingUid) { 639 synchronized (mLock) { 640 if (mEventHistory != null && mEventHistory.getServiceUid() == callingUid) { 641 return mEventHistory; 642 } 643 } 644 645 return null; 646 } 647 648 void dumpLocked(String prefix, PrintWriter pw) { 649 final String prefix2 = prefix + " "; 650 651 pw.print(prefix); pw.print("User: "); pw.println(mUserId); 652 pw.print(prefix); pw.print("Component: "); pw.println(mInfo != null 653 ? mInfo.getServiceInfo().getComponentName() : null); 654 pw.print(prefix); pw.print("Component from settings: "); 655 pw.println(getComponentNameFromSettings()); 656 pw.print(prefix); pw.print("Default component: "); 657 pw.println(mContext.getString(R.string.config_defaultAutofillService)); 658 pw.print(prefix); pw.print("Disabled: "); pw.println(mDisabled); 659 pw.print(prefix); pw.print("Setup complete: "); pw.println(mSetupComplete); 660 pw.print(prefix); pw.print("Last prune: "); pw.println(mLastPrune); 661 662 final int size = mSessions.size(); 663 if (size == 0) { 664 pw.print(prefix); pw.println("No sessions"); 665 } else { 666 pw.print(prefix); pw.print(size); pw.println(" sessions:"); 667 for (int i = 0; i < size; i++) { 668 pw.print(prefix); pw.print("#"); pw.println(i + 1); 669 mSessions.valueAt(i).dumpLocked(prefix2, pw); 670 } 671 } 672 673 if (mEventHistory == null || mEventHistory.getEvents() == null 674 || mEventHistory.getEvents().size() == 0) { 675 pw.print(prefix); pw.println("No event on last fill response"); 676 } else { 677 pw.print(prefix); pw.println("Events of last fill response:"); 678 pw.print(prefix); 679 680 int numEvents = mEventHistory.getEvents().size(); 681 for (int i = 0; i < numEvents; i++) { 682 final Event event = mEventHistory.getEvents().get(i); 683 pw.println(" " + i + ": eventType=" + event.getType() + " datasetId=" 684 + event.getDatasetId()); 685 } 686 } 687 } 688 689 void destroySessionsLocked() { 690 if (mSessions.size() == 0) { 691 mUi.destroyAll(null, null, false); 692 return; 693 } 694 while (mSessions.size() > 0) { 695 mSessions.valueAt(0).forceRemoveSelfLocked(); 696 } 697 } 698 699 // TODO(b/64940307): remove this method if SaveUI is refactored to be attached on activities 700 void destroyFinishedSessionsLocked() { 701 final int sessionCount = mSessions.size(); 702 for (int i = sessionCount - 1; i >= 0; i--) { 703 final Session session = mSessions.valueAt(i); 704 if (session.isSavingLocked()) { 705 if (sDebug) Slog.d(TAG, "destroyFinishedSessionsLocked(): " + session.id); 706 session.forceRemoveSelfLocked(); 707 } 708 } 709 } 710 711 void listSessionsLocked(ArrayList<String> output) { 712 final int numSessions = mSessions.size(); 713 for (int i = 0; i < numSessions; i++) { 714 output.add((mInfo != null ? mInfo.getServiceInfo().getComponentName() 715 : null) + ":" + mSessions.keyAt(i)); 716 } 717 } 718 719 private void sendStateToClients(boolean resetClient) { 720 final RemoteCallbackList<IAutoFillManagerClient> clients; 721 final int userClientCount; 722 synchronized (mLock) { 723 if (mClients == null) { 724 return; 725 } 726 clients = mClients; 727 userClientCount = clients.beginBroadcast(); 728 } 729 try { 730 for (int i = 0; i < userClientCount; i++) { 731 final IAutoFillManagerClient client = clients.getBroadcastItem(i); 732 try { 733 final boolean resetSession; 734 synchronized (mLock) { 735 resetSession = resetClient || isClientSessionDestroyedLocked(client); 736 } 737 client.setState(isEnabled(), resetSession, resetClient); 738 } catch (RemoteException re) { 739 /* ignore */ 740 } 741 } 742 } finally { 743 clients.finishBroadcast(); 744 } 745 } 746 747 private boolean isClientSessionDestroyedLocked(IAutoFillManagerClient client) { 748 final int sessionCount = mSessions.size(); 749 for (int i = 0; i < sessionCount; i++) { 750 final Session session = mSessions.valueAt(i); 751 if (session.getClient().equals(client)) { 752 return session.isDestroyed(); 753 } 754 } 755 return true; 756 } 757 758 boolean isEnabled() { 759 return mSetupComplete && mInfo != null && !mDisabled; 760 } 761 762 @Override 763 public String toString() { 764 return "AutofillManagerServiceImpl: [userId=" + mUserId 765 + ", component=" + (mInfo != null 766 ? mInfo.getServiceInfo().getComponentName() : null) + "]"; 767 } 768 769 /** Task used to prune abandoned session */ 770 private class PruneTask extends AsyncTask<Void, Void, Void> { 771 @Override 772 protected Void doInBackground(Void... ignored) { 773 int numSessionsToRemove; 774 775 SparseArray<IBinder> sessionsToRemove; 776 777 synchronized (mLock) { 778 numSessionsToRemove = mSessions.size(); 779 sessionsToRemove = new SparseArray<>(numSessionsToRemove); 780 781 for (int i = 0; i < numSessionsToRemove; i++) { 782 Session session = mSessions.valueAt(i); 783 784 sessionsToRemove.put(session.id, session.getActivityTokenLocked()); 785 } 786 } 787 788 IActivityManager am = ActivityManager.getService(); 789 790 // Only remove sessions which's activities are not known to the activity manager anymore 791 for (int i = 0; i < numSessionsToRemove; i++) { 792 try { 793 // The activity manager cannot resolve activities that have been removed 794 if (am.getActivityClassForToken(sessionsToRemove.valueAt(i)) != null) { 795 sessionsToRemove.removeAt(i); 796 i--; 797 numSessionsToRemove--; 798 } 799 } catch (RemoteException e) { 800 Slog.w(TAG, "Cannot figure out if activity is finished", e); 801 } 802 } 803 804 synchronized (mLock) { 805 for (int i = 0; i < numSessionsToRemove; i++) { 806 Session sessionToRemove = mSessions.get(sessionsToRemove.keyAt(i)); 807 808 if (sessionToRemove != null && sessionsToRemove.valueAt(i) 809 == sessionToRemove.getActivityTokenLocked()) { 810 if (sessionToRemove.isSavingLocked()) { 811 if (sVerbose) { 812 Slog.v(TAG, "Session " + sessionToRemove.id + " is saving"); 813 } 814 } else { 815 if (sDebug) { 816 Slog.i(TAG, "Prune session " + sessionToRemove.id + " (" 817 + sessionToRemove.getActivityTokenLocked() + ")"); 818 } 819 sessionToRemove.removeSelfLocked(); 820 } 821 } 822 } 823 } 824 825 return null; 826 } 827 } 828} 829