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