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