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