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