AutofillManagerServiceImpl.java revision 51e29da65e1872745a185284556f4947463ec07d
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.ServiceInfo; 36import android.graphics.Rect; 37import android.graphics.drawable.Drawable; 38import android.os.AsyncTask; 39import android.os.Binder; 40import android.os.Bundle; 41import android.os.IBinder; 42import android.os.Looper; 43import android.os.RemoteCallbackList; 44import android.os.RemoteException; 45import android.os.SystemClock; 46import android.os.UserManager; 47import android.provider.Settings; 48import android.service.autofill.AutofillService; 49import android.service.autofill.AutofillServiceInfo; 50import android.service.autofill.FillEventHistory; 51import android.service.autofill.FillEventHistory.Event; 52import android.service.autofill.FillResponse; 53import android.service.autofill.IAutoFillService; 54import android.text.TextUtils; 55import android.util.ArrayMap; 56import android.util.ArraySet; 57import android.util.DebugUtils; 58import android.util.LocalLog; 59import android.util.Slog; 60import android.util.SparseArray; 61import android.util.TimeUtils; 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 * Apps disabled by the service; key is package name, value is when they will be enabled again. 109 */ 110 private ArrayMap<String, Long> mDisabledApps; 111 112 /** 113 * Activities disabled by the service; key is component name, value is when they will be enabled 114 * again. 115 */ 116 private ArrayMap<ComponentName, Long> mDisabledActivities; 117 118 /** 119 * Whether service was disabled for user due to {@link UserManager} restrictions. 120 */ 121 private boolean mDisabled; 122 123 /** 124 * Caches whether the setup completed for the current user. 125 */ 126 @GuardedBy("mLock") 127 private boolean mSetupComplete; 128 129 private final HandlerCaller.Callback mHandlerCallback = (msg) -> { 130 switch (msg.what) { 131 case MSG_SERVICE_SAVE: 132 handleSessionSave(msg.arg1); 133 break; 134 default: 135 Slog.w(TAG, "invalid msg on handler: " + msg); 136 } 137 }; 138 139 private final HandlerCaller mHandlerCaller = new HandlerCaller(null, Looper.getMainLooper(), 140 mHandlerCallback, true); 141 142 /** 143 * Cache of pending {@link Session}s, keyed by sessionId. 144 * 145 * <p>They're kept until the {@link AutofillService} finished handling a request, an error 146 * occurs, or the session is abandoned. 147 */ 148 @GuardedBy("mLock") 149 private final SparseArray<Session> mSessions = new SparseArray<>(); 150 151 /** The last selection */ 152 @GuardedBy("mLock") 153 private FillEventHistory mEventHistory; 154 155 /** When was {@link PruneTask} last executed? */ 156 private long mLastPrune = 0; 157 158 AutofillManagerServiceImpl(Context context, Object lock, LocalLog requestsHistory, 159 LocalLog uiLatencyHistory, int userId, AutoFillUI ui, boolean disabled) { 160 mContext = context; 161 mLock = lock; 162 mRequestsHistory = requestsHistory; 163 mUiLatencyHistory = uiLatencyHistory; 164 mUserId = userId; 165 mUi = ui; 166 updateLocked(disabled); 167 } 168 169 @Nullable 170 CharSequence getServiceName() { 171 final String packageName = getServicePackageName(); 172 if (packageName == null) { 173 return null; 174 } 175 176 try { 177 final PackageManager pm = mContext.getPackageManager(); 178 final ApplicationInfo info = pm.getApplicationInfo(packageName, 0); 179 return pm.getApplicationLabel(info); 180 } catch (Exception e) { 181 Slog.e(TAG, "Could not get label for " + packageName + ": " + e); 182 return packageName; 183 } 184 } 185 186 @Nullable 187 String getServicePackageName() { 188 final ComponentName serviceComponent = getServiceComponentName(); 189 if (serviceComponent != null) { 190 return serviceComponent.getPackageName(); 191 } 192 return null; 193 } 194 195 ComponentName getServiceComponentName() { 196 synchronized (mLock) { 197 if (mInfo == null) { 198 return null; 199 } 200 return mInfo.getServiceInfo().getComponentName(); 201 } 202 } 203 204 private boolean isSetupCompletedLocked() { 205 final String setupComplete = Settings.Secure.getStringForUser( 206 mContext.getContentResolver(), Settings.Secure.USER_SETUP_COMPLETE, mUserId); 207 return "1".equals(setupComplete); 208 } 209 210 private String getComponentNameFromSettings() { 211 return Settings.Secure.getStringForUser( 212 mContext.getContentResolver(), Settings.Secure.AUTOFILL_SERVICE, mUserId); 213 } 214 215 void updateLocked(boolean disabled) { 216 final boolean wasEnabled = isEnabled(); 217 if (sVerbose) { 218 Slog.v(TAG, "updateLocked(u=" + mUserId + "): wasEnabled=" + wasEnabled 219 + ", mSetupComplete= " + mSetupComplete 220 + ", disabled=" + disabled + ", mDisabled=" + mDisabled); 221 } 222 mSetupComplete = isSetupCompletedLocked(); 223 mDisabled = disabled; 224 ComponentName serviceComponent = null; 225 ServiceInfo serviceInfo = null; 226 final String componentName = getComponentNameFromSettings(); 227 if (!TextUtils.isEmpty(componentName)) { 228 try { 229 serviceComponent = ComponentName.unflattenFromString(componentName); 230 serviceInfo = AppGlobals.getPackageManager().getServiceInfo(serviceComponent, 231 0, mUserId); 232 if (serviceInfo == null) { 233 Slog.e(TAG, "Bad AutofillService name: " + componentName); 234 } 235 } catch (RuntimeException | RemoteException e) { 236 Slog.e(TAG, "Error getting service info for '" + componentName + "': " + e); 237 serviceInfo = null; 238 } 239 } 240 try { 241 if (serviceInfo != null) { 242 mInfo = new AutofillServiceInfo(mContext.getPackageManager(), 243 serviceComponent, mUserId); 244 if (sDebug) Slog.d(TAG, "Set component for user " + mUserId + " as " + mInfo); 245 } else { 246 mInfo = null; 247 if (sDebug) { 248 Slog.d(TAG, "Reset component for user " + mUserId + " (" + componentName + ")"); 249 } 250 } 251 } catch (Exception e) { 252 Slog.e(TAG, "Bad AutofillServiceInfo for '" + componentName + "': " + e); 253 mInfo = null; 254 } 255 final boolean isEnabled = isEnabled(); 256 if (wasEnabled != isEnabled) { 257 if (!isEnabled) { 258 final int sessionCount = mSessions.size(); 259 for (int i = sessionCount - 1; i >= 0; i--) { 260 final Session session = mSessions.valueAt(i); 261 session.removeSelfLocked(); 262 } 263 } 264 sendStateToClients(false); 265 } 266 } 267 268 boolean addClientLocked(IAutoFillManagerClient client) { 269 if (mClients == null) { 270 mClients = new RemoteCallbackList<>(); 271 } 272 mClients.register(client); 273 return isEnabled(); 274 } 275 276 void setAuthenticationResultLocked(Bundle data, int sessionId, int authenticationId, int uid) { 277 if (!isEnabled()) { 278 return; 279 } 280 final Session session = mSessions.get(sessionId); 281 if (session != null && uid == session.uid) { 282 session.setAuthenticationResultLocked(data, authenticationId); 283 } 284 } 285 286 void setHasCallback(int sessionId, int uid, boolean hasIt) { 287 if (!isEnabled()) { 288 return; 289 } 290 final Session session = mSessions.get(sessionId); 291 if (session != null && uid == session.uid) { 292 synchronized (mLock) { 293 session.setHasCallbackLocked(hasIt); 294 } 295 } 296 } 297 298 int startSessionLocked(@NonNull IBinder activityToken, int uid, 299 @NonNull IBinder appCallbackToken, @NonNull AutofillId autofillId, 300 @NonNull Rect virtualBounds, @Nullable AutofillValue value, boolean hasCallback, 301 int flags, @NonNull ComponentName componentName) { 302 if (!isEnabled()) { 303 return 0; 304 } 305 306 final String shortComponentName = componentName.toShortString(); 307 308 if (isAutofillDisabledLocked(componentName)) { 309 if (sDebug) { 310 Slog.d(TAG, "startSession(" + shortComponentName 311 + "): ignored because disabled by service"); 312 } 313 314 final IAutoFillManagerClient client = IAutoFillManagerClient.Stub 315 .asInterface(appCallbackToken); 316 try { 317 client.setSessionFinished(AutofillManager.STATE_DISABLED_BY_SERVICE); 318 } catch (RemoteException e) { 319 Slog.w(TAG, "Could not notify " + shortComponentName + " that it's disabled: " + e); 320 } 321 322 return NO_SESSION; 323 } 324 325 if (sVerbose) Slog.v(TAG, "startSession(): token=" + activityToken + ", flags=" + flags); 326 327 // Occasionally clean up abandoned sessions 328 pruneAbandonedSessionsLocked(); 329 330 final Session newSession = createSessionByTokenLocked(activityToken, uid, appCallbackToken, 331 hasCallback, componentName); 332 if (newSession == null) { 333 return NO_SESSION; 334 } 335 336 final String historyItem = 337 "id=" + newSession.id + " uid=" + uid + " a=" + shortComponentName 338 + " s=" + mInfo.getServiceInfo().packageName 339 + " u=" + mUserId + " i=" + autofillId + " b=" + virtualBounds 340 + " hc=" + hasCallback + " f=" + flags; 341 mRequestsHistory.log(historyItem); 342 343 newSession.updateLocked(autofillId, virtualBounds, value, ACTION_START_SESSION, flags); 344 345 return newSession.id; 346 } 347 348 /** 349 * Remove abandoned sessions if needed. 350 */ 351 private void pruneAbandonedSessionsLocked() { 352 long now = System.currentTimeMillis(); 353 if (mLastPrune < now - MAX_ABANDONED_SESSION_MILLIS) { 354 mLastPrune = now; 355 356 if (mSessions.size() > 0) { 357 (new PruneTask()).execute(); 358 } 359 } 360 } 361 362 void finishSessionLocked(int sessionId, int uid) { 363 if (!isEnabled()) { 364 return; 365 } 366 367 final Session session = mSessions.get(sessionId); 368 if (session == null || uid != session.uid) { 369 if (sVerbose) { 370 Slog.v(TAG, "finishSessionLocked(): no session for " + sessionId + "(" + uid + ")"); 371 } 372 return; 373 } 374 375 session.logContextCommittedLocked(); 376 377 final boolean finished = session.showSaveLocked(); 378 if (sVerbose) Slog.v(TAG, "finishSessionLocked(): session finished on save? " + finished); 379 380 if (finished) { 381 session.removeSelfLocked(); 382 } 383 } 384 385 void cancelSessionLocked(int sessionId, int uid) { 386 if (!isEnabled()) { 387 return; 388 } 389 390 final Session session = mSessions.get(sessionId); 391 if (session == null || uid != session.uid) { 392 Slog.w(TAG, "cancelSessionLocked(): no session for " + sessionId + "(" + uid + ")"); 393 return; 394 } 395 session.removeSelfLocked(); 396 } 397 398 void disableOwnedAutofillServicesLocked(int uid) { 399 Slog.i(TAG, "disableOwnedServices(" + uid + "): " + mInfo); 400 if (mInfo == null) return; 401 402 final ServiceInfo serviceInfo = mInfo.getServiceInfo(); 403 if (serviceInfo.applicationInfo.uid != uid) { 404 Slog.w(TAG, "disableOwnedServices(): ignored when called by UID " + uid 405 + " instead of " + serviceInfo.applicationInfo.uid 406 + " for service " + mInfo); 407 return; 408 } 409 410 411 final long identity = Binder.clearCallingIdentity(); 412 try { 413 final String autoFillService = getComponentNameFromSettings(); 414 final ComponentName componentName = serviceInfo.getComponentName(); 415 if (componentName.equals(ComponentName.unflattenFromString(autoFillService))) { 416 mMetricsLogger.action(MetricsEvent.AUTOFILL_SERVICE_DISABLED_SELF, 417 componentName.getPackageName()); 418 Settings.Secure.putStringForUser(mContext.getContentResolver(), 419 Settings.Secure.AUTOFILL_SERVICE, null, mUserId); 420 destroySessionsLocked(); 421 } else { 422 Slog.w(TAG, "disableOwnedServices(): ignored because current service (" 423 + serviceInfo + ") does not match Settings (" + autoFillService + ")"); 424 } 425 } finally { 426 Binder.restoreCallingIdentity(identity); 427 } 428 } 429 430 private Session createSessionByTokenLocked(@NonNull IBinder activityToken, int uid, 431 @NonNull IBinder appCallbackToken, boolean hasCallback, 432 @NonNull ComponentName componentName) { 433 // use random ids so that one app cannot know that another app creates sessions 434 int sessionId; 435 int tries = 0; 436 do { 437 tries++; 438 if (tries > MAX_SESSION_ID_CREATE_TRIES) { 439 Slog.w(TAG, "Cannot create session in " + MAX_SESSION_ID_CREATE_TRIES + " tries"); 440 return null; 441 } 442 443 sessionId = sRandom.nextInt(); 444 } while (sessionId == NO_SESSION || mSessions.indexOfKey(sessionId) >= 0); 445 446 final Session newSession = new Session(this, mUi, mContext, mHandlerCaller, mUserId, mLock, 447 sessionId, uid, activityToken, appCallbackToken, hasCallback, 448 mUiLatencyHistory, mInfo.getServiceInfo().getComponentName(), componentName); 449 mSessions.put(newSession.id, newSession); 450 451 return newSession; 452 } 453 454 /** 455 * Restores a session after an activity was temporarily destroyed. 456 * 457 * @param sessionId The id of the session to restore 458 * @param uid UID of the process that tries to restore the session 459 * @param activityToken The new instance of the activity 460 * @param appCallback The callbacks to the activity 461 */ 462 boolean restoreSession(int sessionId, int uid, @NonNull IBinder activityToken, 463 @NonNull IBinder appCallback) { 464 final Session session = mSessions.get(sessionId); 465 466 if (session == null || uid != session.uid) { 467 return false; 468 } else { 469 session.switchActivity(activityToken, appCallback); 470 return true; 471 } 472 } 473 474 /** 475 * Updates a session and returns whether it should be restarted. 476 */ 477 boolean updateSessionLocked(int sessionId, int uid, AutofillId autofillId, Rect virtualBounds, 478 AutofillValue value, int action, int flags) { 479 final Session session = mSessions.get(sessionId); 480 if (session == null || session.uid != uid) { 481 if ((flags & FLAG_MANUAL_REQUEST) != 0) { 482 if (sDebug) { 483 Slog.d(TAG, "restarting session " + sessionId + " due to manual request on " 484 + autofillId); 485 } 486 return true; 487 } 488 if (sVerbose) { 489 Slog.v(TAG, "updateSessionLocked(): session gone for " + sessionId 490 + "(" + uid + ")"); 491 } 492 return false; 493 } 494 495 session.updateLocked(autofillId, virtualBounds, value, action, flags); 496 return false; 497 } 498 499 void removeSessionLocked(int sessionId) { 500 mSessions.remove(sessionId); 501 } 502 503 private void handleSessionSave(int sessionId) { 504 synchronized (mLock) { 505 final Session session = mSessions.get(sessionId); 506 if (session == null) { 507 Slog.w(TAG, "handleSessionSave(): already gone: " + sessionId); 508 509 return; 510 } 511 session.callSaveLocked(); 512 } 513 } 514 515 void onPendingSaveUi(int operation, @NonNull IBinder token) { 516 if (sVerbose) Slog.v(TAG, "onPendingSaveUi(" + operation + "): " + token); 517 synchronized (mLock) { 518 final int sessionCount = mSessions.size(); 519 for (int i = sessionCount - 1; i >= 0; i--) { 520 final Session session = mSessions.valueAt(i); 521 if (session.isSaveUiPendingForTokenLocked(token)) { 522 session.onPendingSaveUi(operation, token); 523 return; 524 } 525 } 526 } 527 if (sDebug) { 528 Slog.d(TAG, "No pending Save UI for token " + token + " and operation " 529 + DebugUtils.flagsToString(AutofillManager.class, "PENDING_UI_OPERATION_", 530 operation)); 531 } 532 } 533 534 void destroyLocked() { 535 if (sVerbose) Slog.v(TAG, "destroyLocked()"); 536 537 final int numSessions = mSessions.size(); 538 final ArraySet<RemoteFillService> remoteFillServices = new ArraySet<>(numSessions); 539 for (int i = 0; i < numSessions; i++) { 540 final RemoteFillService remoteFillService = mSessions.valueAt(i).destroyLocked(); 541 if (remoteFillService != null) { 542 remoteFillServices.add(remoteFillService); 543 } 544 } 545 mSessions.clear(); 546 for (int i = 0; i < remoteFillServices.size(); i++) { 547 remoteFillServices.valueAt(i).destroy(); 548 } 549 550 sendStateToClients(true); 551 } 552 553 @NonNull 554 CharSequence getServiceLabel() { 555 return mInfo.getServiceInfo().loadLabel(mContext.getPackageManager()); 556 } 557 558 @NonNull 559 Drawable getServiceIcon() { 560 return mInfo.getServiceInfo().loadIcon(mContext.getPackageManager()); 561 } 562 563 /** 564 * Initializes the last fill selection after an autofill service returned a new 565 * {@link FillResponse}. 566 */ 567 void setLastResponse(int serviceUid, int sessionId, @NonNull FillResponse response) { 568 synchronized (mLock) { 569 mEventHistory = new FillEventHistory(serviceUid, sessionId, response.getClientState()); 570 } 571 } 572 573 /** 574 * Resets the last fill selection. 575 */ 576 void resetLastResponse() { 577 synchronized (mLock) { 578 mEventHistory = null; 579 } 580 } 581 582 private boolean isValidEventLocked(String method, int sessionId) { 583 if (mEventHistory == null) { 584 Slog.w(TAG, method + ": not logging event because history is null"); 585 return false; 586 } 587 if (sessionId != mEventHistory.getSessionId()) { 588 if (sDebug) { 589 Slog.d(TAG, method + ": not logging event for session " + sessionId 590 + " because tracked session is " + mEventHistory.getSessionId()); 591 } 592 return false; 593 } 594 return true; 595 } 596 597 /** 598 * Updates the last fill selection when an authentication was selected. 599 */ 600 void setAuthenticationSelected(int sessionId, @Nullable Bundle clientState) { 601 synchronized (mLock) { 602 if (isValidEventLocked("setAuthenticationSelected()", sessionId)) { 603 mEventHistory.addEvent( 604 new Event(Event.TYPE_AUTHENTICATION_SELECTED, null, clientState, null, null, 605 null, null, null, null)); 606 } 607 } 608 } 609 610 /** 611 * Updates the last fill selection when an dataset authentication was selected. 612 */ 613 void logDatasetAuthenticationSelected(@Nullable String selectedDataset, int sessionId, 614 @Nullable Bundle clientState) { 615 synchronized (mLock) { 616 if (isValidEventLocked("logDatasetAuthenticationSelected()", sessionId)) { 617 mEventHistory.addEvent( 618 new Event(Event.TYPE_DATASET_AUTHENTICATION_SELECTED, selectedDataset, 619 clientState, null, null, null, null, null, null)); 620 } 621 } 622 } 623 624 /** 625 * Updates the last fill selection when an save Ui is shown. 626 */ 627 void logSaveShown(int sessionId, @Nullable Bundle clientState) { 628 synchronized (mLock) { 629 if (isValidEventLocked("logSaveShown()", sessionId)) { 630 mEventHistory.addEvent(new Event(Event.TYPE_SAVE_SHOWN, null, clientState, null, 631 null, null, null, null, null)); 632 } 633 } 634 } 635 636 /** 637 * Updates the last fill response when a dataset was selected. 638 */ 639 void logDatasetSelected(@Nullable String selectedDataset, int sessionId, 640 @Nullable Bundle clientState) { 641 synchronized (mLock) { 642 if (isValidEventLocked("logDatasetSelected()", sessionId)) { 643 mEventHistory.addEvent( 644 new Event(Event.TYPE_DATASET_SELECTED, selectedDataset, clientState, null, 645 null, null, null, null, null)); 646 } 647 } 648 } 649 650 /** 651 * Updates the last fill response when an autofill context is committed. 652 */ 653 void logContextCommitted(int sessionId, @Nullable Bundle clientState, 654 @Nullable ArrayList<String> selectedDatasets, 655 @Nullable ArraySet<String> ignoredDatasets, 656 @Nullable ArrayList<AutofillId> changedFieldIds, 657 @Nullable ArrayList<String> changedDatasetIds, 658 @Nullable ArrayList<AutofillId> manuallyFilledFieldIds, 659 @Nullable ArrayList<ArrayList<String>> manuallyFilledDatasetIds) { 660 synchronized (mLock) { 661 if (isValidEventLocked("logDatasetNotSelected()", sessionId)) { 662 mEventHistory.addEvent(new Event(Event.TYPE_CONTEXT_COMMITTED, null, 663 clientState, selectedDatasets, ignoredDatasets, 664 changedFieldIds, changedDatasetIds, 665 manuallyFilledFieldIds, manuallyFilledDatasetIds)); 666 } 667 } 668 } 669 670 /** 671 * Gets the fill event history. 672 * 673 * @param callingUid The calling uid 674 * 675 * @return The history or {@code null} if there is none. 676 */ 677 FillEventHistory getFillEventHistory(int callingUid) { 678 synchronized (mLock) { 679 if (mEventHistory != null && mEventHistory.getServiceUid() == callingUid) { 680 return mEventHistory; 681 } 682 } 683 684 return null; 685 } 686 687 void dumpLocked(String prefix, PrintWriter pw) { 688 final String prefix2 = prefix + " "; 689 690 pw.print(prefix); pw.print("User: "); pw.println(mUserId); 691 pw.print(prefix); pw.print("Component: "); pw.println(mInfo != null 692 ? mInfo.getServiceInfo().getComponentName() : null); 693 pw.print(prefix); pw.print("Component from settings: "); 694 pw.println(getComponentNameFromSettings()); 695 pw.print(prefix); pw.print("Default component: "); 696 pw.println(mContext.getString(R.string.config_defaultAutofillService)); 697 pw.print(prefix); pw.print("Disabled: "); pw.println(mDisabled); 698 pw.print(prefix); pw.print("Setup complete: "); pw.println(mSetupComplete); 699 pw.print(prefix); pw.print("Last prune: "); pw.println(mLastPrune); 700 701 pw.print(prefix); pw.print("Disabled apps: "); 702 703 if (mDisabledApps == null) { 704 pw.println("N/A"); 705 } else { 706 final int size = mDisabledApps.size(); 707 pw.println(size); 708 final StringBuilder builder = new StringBuilder(); 709 final long now = SystemClock.elapsedRealtime(); 710 for (int i = 0; i < size; i++) { 711 final String packageName = mDisabledApps.keyAt(i); 712 final long expiration = mDisabledApps.valueAt(i); 713 builder.append(prefix).append(prefix) 714 .append(i).append(". ").append(packageName).append(": "); 715 TimeUtils.formatDuration((expiration - now), builder); 716 builder.append('\n'); 717 } 718 pw.println(builder); 719 } 720 721 pw.print(prefix); pw.print("Disabled activities: "); 722 723 if (mDisabledActivities == null) { 724 pw.println("N/A"); 725 } else { 726 final int size = mDisabledActivities.size(); 727 pw.println(size); 728 final StringBuilder builder = new StringBuilder(); 729 final long now = SystemClock.elapsedRealtime(); 730 for (int i = 0; i < size; i++) { 731 final ComponentName component = mDisabledActivities.keyAt(i); 732 final long expiration = mDisabledActivities.valueAt(i); 733 builder.append(prefix).append(prefix) 734 .append(i).append(". ").append(component).append(": "); 735 TimeUtils.formatDuration((expiration - now), builder); 736 builder.append('\n'); 737 } 738 pw.println(builder); 739 } 740 741 final int size = mSessions.size(); 742 if (size == 0) { 743 pw.print(prefix); pw.println("No sessions"); 744 } else { 745 pw.print(prefix); pw.print(size); pw.println(" sessions:"); 746 for (int i = 0; i < size; i++) { 747 pw.print(prefix); pw.print("#"); pw.println(i + 1); 748 mSessions.valueAt(i).dumpLocked(prefix2, pw); 749 } 750 } 751 752 if (mEventHistory == null || mEventHistory.getEvents() == null 753 || mEventHistory.getEvents().size() == 0) { 754 pw.print(prefix); pw.println("No event on last fill response"); 755 } else { 756 pw.print(prefix); pw.println("Events of last fill response:"); 757 pw.print(prefix); 758 759 int numEvents = mEventHistory.getEvents().size(); 760 for (int i = 0; i < numEvents; i++) { 761 final Event event = mEventHistory.getEvents().get(i); 762 pw.println(" " + i + ": eventType=" + event.getType() + " datasetId=" 763 + event.getDatasetId()); 764 } 765 } 766 } 767 768 void destroySessionsLocked() { 769 if (mSessions.size() == 0) { 770 mUi.destroyAll(null, null, false); 771 return; 772 } 773 while (mSessions.size() > 0) { 774 mSessions.valueAt(0).forceRemoveSelfLocked(); 775 } 776 } 777 778 // TODO(b/64940307): remove this method if SaveUI is refactored to be attached on activities 779 void destroyFinishedSessionsLocked() { 780 final int sessionCount = mSessions.size(); 781 for (int i = sessionCount - 1; i >= 0; i--) { 782 final Session session = mSessions.valueAt(i); 783 if (session.isSavingLocked()) { 784 if (sDebug) Slog.d(TAG, "destroyFinishedSessionsLocked(): " + session.id); 785 session.forceRemoveSelfLocked(); 786 } 787 } 788 } 789 790 void listSessionsLocked(ArrayList<String> output) { 791 final int numSessions = mSessions.size(); 792 for (int i = 0; i < numSessions; i++) { 793 output.add((mInfo != null ? mInfo.getServiceInfo().getComponentName() 794 : null) + ":" + mSessions.keyAt(i)); 795 } 796 } 797 798 private void sendStateToClients(boolean resetClient) { 799 final RemoteCallbackList<IAutoFillManagerClient> clients; 800 final int userClientCount; 801 synchronized (mLock) { 802 if (mClients == null) { 803 return; 804 } 805 clients = mClients; 806 userClientCount = clients.beginBroadcast(); 807 } 808 try { 809 for (int i = 0; i < userClientCount; i++) { 810 final IAutoFillManagerClient client = clients.getBroadcastItem(i); 811 try { 812 final boolean resetSession; 813 synchronized (mLock) { 814 resetSession = resetClient || isClientSessionDestroyedLocked(client); 815 } 816 int flags = 0; 817 if (isEnabled()) { 818 flags |= AutofillManager.SET_STATE_FLAG_ENABLED; 819 } 820 if (resetSession) { 821 flags |= AutofillManager.SET_STATE_FLAG_RESET_SESSION; 822 } 823 if (resetClient) { 824 flags |= AutofillManager.SET_STATE_FLAG_RESET_CLIENT; 825 } 826 if (sDebug) { 827 flags |= AutofillManager.SET_STATE_FLAG_DEBUG; 828 } 829 if (sVerbose) { 830 flags |= AutofillManager.SET_STATE_FLAG_VERBOSE; 831 } 832 client.setState(flags); 833 } catch (RemoteException re) { 834 /* ignore */ 835 } 836 } 837 } finally { 838 clients.finishBroadcast(); 839 } 840 } 841 842 private boolean isClientSessionDestroyedLocked(IAutoFillManagerClient client) { 843 final int sessionCount = mSessions.size(); 844 for (int i = 0; i < sessionCount; i++) { 845 final Session session = mSessions.valueAt(i); 846 if (session.getClient().equals(client)) { 847 return session.isDestroyed(); 848 } 849 } 850 return true; 851 } 852 853 boolean isEnabled() { 854 return mSetupComplete && mInfo != null && !mDisabled; 855 } 856 857 /** 858 * Called by {@link Session} when service asked to disable autofill for an app. 859 */ 860 void disableAutofillForApp(@NonNull String packageName, long duration) { 861 synchronized (mLock) { 862 if (mDisabledApps == null) { 863 mDisabledApps = new ArrayMap<>(1); 864 } 865 long expiration = SystemClock.elapsedRealtime() + duration; 866 // Protect it against overflow 867 if (expiration < 0) { 868 expiration = Long.MAX_VALUE; 869 } 870 mDisabledApps.put(packageName, expiration); 871 int intDuration = duration > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) duration; 872 mMetricsLogger.write(Helper.newLogMaker(MetricsEvent.AUTOFILL_SERVICE_DISABLED_APP, 873 packageName, getServicePackageName()) 874 .setCounterValue(intDuration)); 875 } 876 } 877 878 /** 879 * Called by {@link Session} when service asked to disable autofill an app. 880 */ 881 void disableAutofillForActivity(@NonNull ComponentName componentName, long duration) { 882 synchronized (mLock) { 883 if (mDisabledActivities == null) { 884 mDisabledActivities = new ArrayMap<>(1); 885 } 886 long expiration = SystemClock.elapsedRealtime() + duration; 887 // Protect it against overflow 888 if (expiration < 0) { 889 expiration = Long.MAX_VALUE; 890 } 891 mDisabledActivities.put(componentName, expiration); 892 int intDuration = duration > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) duration; 893 mMetricsLogger.write(Helper.newLogMaker(MetricsEvent.AUTOFILL_SERVICE_DISABLED_ACTIVITY, 894 componentName.getPackageName(), getServicePackageName()) 895 .addTaggedData(MetricsEvent.FIELD_CLASS_NAME, componentName.getClassName()) 896 .setCounterValue(intDuration)); 897 } 898 } 899 900 /** 901 * Checks if autofill is disabled by service to the given activity. 902 */ 903 private boolean isAutofillDisabledLocked(@NonNull ComponentName componentName) { 904 // Check activities first. 905 long elapsedTime = 0; 906 if (mDisabledActivities != null) { 907 elapsedTime = SystemClock.elapsedRealtime(); 908 final Long expiration = mDisabledActivities.get(componentName); 909 if (expiration != null) { 910 if (expiration >= elapsedTime) return true; 911 // Restriction expired - clean it up. 912 if (sVerbose) { 913 Slog.v(TAG, "Removing " + componentName.toShortString() + " from disabled list"); 914 } 915 mDisabledActivities.remove(componentName); 916 } 917 } 918 919 // Then check apps. 920 final String packageName = componentName.getPackageName(); 921 if (mDisabledApps == null) return false; 922 923 final Long expiration = mDisabledApps.get(packageName); 924 if (expiration == null) return false; 925 926 if (elapsedTime == 0) { 927 elapsedTime = SystemClock.elapsedRealtime(); 928 } 929 930 if (expiration >= elapsedTime) return true; 931 932 // Restriction expired - clean it up. 933 if (sVerbose) Slog.v(TAG, "Removing " + packageName + " from disabled list"); 934 mDisabledApps.remove(packageName); 935 return false; 936 } 937 938 @Override 939 public String toString() { 940 return "AutofillManagerServiceImpl: [userId=" + mUserId 941 + ", component=" + (mInfo != null 942 ? mInfo.getServiceInfo().getComponentName() : null) + "]"; 943 } 944 945 /** Task used to prune abandoned session */ 946 private class PruneTask extends AsyncTask<Void, Void, Void> { 947 @Override 948 protected Void doInBackground(Void... ignored) { 949 int numSessionsToRemove; 950 951 SparseArray<IBinder> sessionsToRemove; 952 953 synchronized (mLock) { 954 numSessionsToRemove = mSessions.size(); 955 sessionsToRemove = new SparseArray<>(numSessionsToRemove); 956 957 for (int i = 0; i < numSessionsToRemove; i++) { 958 Session session = mSessions.valueAt(i); 959 960 sessionsToRemove.put(session.id, session.getActivityTokenLocked()); 961 } 962 } 963 964 IActivityManager am = ActivityManager.getService(); 965 966 // Only remove sessions which's activities are not known to the activity manager anymore 967 for (int i = 0; i < numSessionsToRemove; i++) { 968 try { 969 // The activity manager cannot resolve activities that have been removed 970 if (am.getActivityClassForToken(sessionsToRemove.valueAt(i)) != null) { 971 sessionsToRemove.removeAt(i); 972 i--; 973 numSessionsToRemove--; 974 } 975 } catch (RemoteException e) { 976 Slog.w(TAG, "Cannot figure out if activity is finished", e); 977 } 978 } 979 980 synchronized (mLock) { 981 for (int i = 0; i < numSessionsToRemove; i++) { 982 Session sessionToRemove = mSessions.get(sessionsToRemove.keyAt(i)); 983 984 if (sessionToRemove != null && sessionsToRemove.valueAt(i) 985 == sessionToRemove.getActivityTokenLocked()) { 986 if (sessionToRemove.isSavingLocked()) { 987 if (sVerbose) { 988 Slog.v(TAG, "Session " + sessionToRemove.id + " is saving"); 989 } 990 } else { 991 if (sDebug) { 992 Slog.i(TAG, "Prune session " + sessionToRemove.id + " (" 993 + sessionToRemove.getActivityTokenLocked() + ")"); 994 } 995 sessionToRemove.removeSelfLocked(); 996 } 997 } 998 } 999 } 1000 1001 return null; 1002 } 1003 } 1004} 1005