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