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 17 package com.android.server.autofill; 18 19 import static android.service.autofill.FillRequest.FLAG_MANUAL_REQUEST; 20 import static android.view.autofill.AutofillManager.ACTION_START_SESSION; 21 import static android.view.autofill.AutofillManager.FLAG_ADD_CLIENT_ENABLED; 22 import static android.view.autofill.AutofillManager.FLAG_ADD_CLIENT_ENABLED_FOR_AUGMENTED_AUTOFILL_ONLY; 23 import static android.view.autofill.AutofillManager.NO_SESSION; 24 import static android.view.autofill.AutofillManager.RECEIVER_FLAG_SESSION_FOR_AUGMENTED_AUTOFILL_ONLY; 25 26 import static com.android.server.autofill.Helper.sDebug; 27 import static com.android.server.autofill.Helper.sVerbose; 28 29 import android.annotation.NonNull; 30 import android.annotation.Nullable; 31 import android.app.ActivityManagerInternal; 32 import android.app.ActivityTaskManager; 33 import android.app.IActivityTaskManager; 34 import android.content.ComponentName; 35 import android.content.pm.PackageManager; 36 import android.content.pm.PackageManager.NameNotFoundException; 37 import android.content.pm.ServiceInfo; 38 import android.graphics.Rect; 39 import android.metrics.LogMaker; 40 import android.os.AsyncTask; 41 import android.os.Binder; 42 import android.os.Bundle; 43 import android.os.Handler; 44 import android.os.IBinder; 45 import android.os.Looper; 46 import android.os.Process; 47 import android.os.RemoteCallbackList; 48 import android.os.RemoteException; 49 import android.os.SystemClock; 50 import android.os.UserHandle; 51 import android.provider.Settings; 52 import android.service.autofill.AutofillService; 53 import android.service.autofill.AutofillServiceInfo; 54 import android.service.autofill.FieldClassification; 55 import android.service.autofill.FieldClassification.Match; 56 import android.service.autofill.FillEventHistory; 57 import android.service.autofill.FillEventHistory.Event; 58 import android.service.autofill.FillResponse; 59 import android.service.autofill.IAutoFillService; 60 import android.service.autofill.SaveInfo; 61 import android.service.autofill.UserData; 62 import android.util.ArrayMap; 63 import android.util.ArraySet; 64 import android.util.DebugUtils; 65 import android.util.LocalLog; 66 import android.util.Pair; 67 import android.util.Slog; 68 import android.util.SparseArray; 69 import android.util.TimeUtils; 70 import android.view.autofill.AutofillId; 71 import android.view.autofill.AutofillManager; 72 import android.view.autofill.AutofillManager.SmartSuggestionMode; 73 import android.view.autofill.AutofillValue; 74 import android.view.autofill.IAutoFillManagerClient; 75 76 import com.android.internal.R; 77 import com.android.internal.annotations.GuardedBy; 78 import com.android.internal.logging.MetricsLogger; 79 import com.android.internal.logging.nano.MetricsProto.MetricsEvent; 80 import com.android.server.LocalServices; 81 import com.android.server.autofill.AutofillManagerService.AutofillCompatState; 82 import com.android.server.autofill.RemoteAugmentedAutofillService.RemoteAugmentedAutofillServiceCallbacks; 83 import com.android.server.autofill.ui.AutoFillUI; 84 import com.android.server.infra.AbstractPerUserSystemService; 85 86 import java.io.PrintWriter; 87 import java.util.ArrayList; 88 import java.util.List; 89 import java.util.Random; 90 91 /** 92 * Bridge between the {@code system_server}'s {@link AutofillManagerService} and the 93 * app's {@link IAutoFillService} implementation. 94 * 95 */ 96 final class AutofillManagerServiceImpl 97 extends AbstractPerUserSystemService<AutofillManagerServiceImpl, AutofillManagerService> { 98 99 private static final String TAG = "AutofillManagerServiceImpl"; 100 private static final int MAX_SESSION_ID_CREATE_TRIES = 2048; 101 102 /** Minimum interval to prune abandoned sessions */ 103 private static final int MAX_ABANDONED_SESSION_MILLIS = 30_000; 104 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 mUiLatencyHistory; 117 private final LocalLog mWtfHistory; 118 private final FieldClassificationStrategy mFieldClassificationStrategy; 119 120 /** 121 * Apps disabled by the service; key is package name, value is when they will be enabled again. 122 */ 123 @GuardedBy("mLock") 124 private ArrayMap<String, Long> mDisabledApps; 125 126 /** 127 * Activities disabled by the service; key is component name, value is when they will be enabled 128 * again. 129 */ 130 @GuardedBy("mLock") 131 private ArrayMap<ComponentName, Long> mDisabledActivities; 132 133 /** 134 * Data used for field classification. 135 */ 136 @GuardedBy("mLock") 137 private UserData mUserData; 138 139 private final Handler mHandler = new Handler(Looper.getMainLooper(), null, true); 140 141 /** 142 * Cache of pending {@link Session}s, keyed by sessionId. 143 * 144 * <p>They're kept until the {@link AutofillService} finished handling a request, an error 145 * occurs, or the session is abandoned. 146 */ 147 @GuardedBy("mLock") 148 private final SparseArray<Session> mSessions = new SparseArray<>(); 149 150 /** The last selection */ 151 @GuardedBy("mLock") 152 private FillEventHistory mEventHistory; 153 154 /** Shared instance, doesn't need to be logged */ 155 private final AutofillCompatState mAutofillCompatState; 156 157 /** When was {@link PruneTask} last executed? */ 158 private long mLastPrune = 0; 159 160 /** 161 * Reference to the {@link RemoteAugmentedAutofillService}, is set on demand. 162 */ 163 @GuardedBy("mLock") 164 @Nullable 165 private RemoteAugmentedAutofillService mRemoteAugmentedAutofillService; 166 167 @GuardedBy("mLock") 168 @Nullable 169 private ServiceInfo mRemoteAugmentedAutofillServiceInfo; 170 AutofillManagerServiceImpl(AutofillManagerService master, Object lock, LocalLog uiLatencyHistory, LocalLog wtfHistory, int userId, AutoFillUI ui, AutofillCompatState autofillCompatState, boolean disabled)171 AutofillManagerServiceImpl(AutofillManagerService master, Object lock, 172 LocalLog uiLatencyHistory, LocalLog wtfHistory, int userId, AutoFillUI ui, 173 AutofillCompatState autofillCompatState, 174 boolean disabled) { 175 super(master, lock, userId); 176 177 mUiLatencyHistory = uiLatencyHistory; 178 mWtfHistory = wtfHistory; 179 mUi = ui; 180 mFieldClassificationStrategy = new FieldClassificationStrategy(getContext(), userId); 181 mAutofillCompatState = autofillCompatState; 182 183 updateLocked(disabled); 184 } 185 186 @GuardedBy("mLock") onBackKeyPressed()187 void onBackKeyPressed() { 188 final RemoteAugmentedAutofillService remoteService = 189 getRemoteAugmentedAutofillServiceLocked(); 190 if (remoteService != null) { 191 remoteService.onDestroyAutofillWindowsRequest(); 192 } 193 } 194 195 @GuardedBy("mLock") 196 @Override // from PerUserSystemService updateLocked(boolean disabled)197 protected boolean updateLocked(boolean disabled) { 198 destroySessionsLocked(); 199 final boolean enabledChanged = super.updateLocked(disabled); 200 if (enabledChanged) { 201 if (!isEnabledLocked()) { 202 final int sessionCount = mSessions.size(); 203 for (int i = sessionCount - 1; i >= 0; i--) { 204 final Session session = mSessions.valueAt(i); 205 session.removeSelfLocked(); 206 } 207 } 208 sendStateToClients(/* resetClient= */ false); 209 } 210 updateRemoteAugmentedAutofillService(); 211 return enabledChanged; 212 } 213 214 @Override // from PerUserSystemService newServiceInfoLocked(@onNull ComponentName serviceComponent)215 protected ServiceInfo newServiceInfoLocked(@NonNull ComponentName serviceComponent) 216 throws NameNotFoundException { 217 mInfo = new AutofillServiceInfo(getContext(), serviceComponent, mUserId); 218 return mInfo.getServiceInfo(); 219 } 220 221 @Nullable getUrlBarResourceIdsForCompatMode(@onNull String packageName)222 String[] getUrlBarResourceIdsForCompatMode(@NonNull String packageName) { 223 return mAutofillCompatState.getUrlBarResourceIds(packageName, mUserId); 224 } 225 226 /** 227 * Adds the client and return the proper flags 228 * 229 * @return {@code 0} if disabled, {@code FLAG_ADD_CLIENT_ENABLED} if enabled (it might be 230 * OR'ed with {@code FLAG_AUGMENTED_AUTOFILL_REQUEST}). 231 */ 232 @GuardedBy("mLock") addClientLocked(IAutoFillManagerClient client, ComponentName componentName)233 int addClientLocked(IAutoFillManagerClient client, ComponentName componentName) { 234 if (mClients == null) { 235 mClients = new RemoteCallbackList<>(); 236 } 237 mClients.register(client); 238 239 if (isEnabledLocked()) return FLAG_ADD_CLIENT_ENABLED; 240 241 // Check if it's enabled for augmented autofill 242 if (isAugmentedAutofillServiceAvailableLocked() 243 && isWhitelistedForAugmentedAutofillLocked(componentName)) { 244 return FLAG_ADD_CLIENT_ENABLED_FOR_AUGMENTED_AUTOFILL_ONLY; 245 } 246 247 // No flags / disabled 248 return 0; 249 } 250 251 @GuardedBy("mLock") removeClientLocked(IAutoFillManagerClient client)252 void removeClientLocked(IAutoFillManagerClient client) { 253 if (mClients != null) { 254 mClients.unregister(client); 255 } 256 } 257 258 @GuardedBy("mLock") setAuthenticationResultLocked(Bundle data, int sessionId, int authenticationId, int uid)259 void setAuthenticationResultLocked(Bundle data, int sessionId, int authenticationId, int uid) { 260 if (!isEnabledLocked()) { 261 return; 262 } 263 final Session session = mSessions.get(sessionId); 264 if (session != null && uid == session.uid) { 265 session.setAuthenticationResultLocked(data, authenticationId); 266 } 267 } 268 setHasCallback(int sessionId, int uid, boolean hasIt)269 void setHasCallback(int sessionId, int uid, boolean hasIt) { 270 if (!isEnabledLocked()) { 271 return; 272 } 273 final Session session = mSessions.get(sessionId); 274 if (session != null && uid == session.uid) { 275 synchronized (mLock) { 276 session.setHasCallbackLocked(hasIt); 277 } 278 } 279 } 280 281 /** 282 * Starts a new session. 283 * 284 * @return {@code long} whose right-most 32 bits represent the session id (which is always 285 * non-negative), and the left-most contains extra flags (currently either {@code 0} or 286 * {@link AutofillManager#RECEIVER_FLAG_SESSION_FOR_AUGMENTED_AUTOFILL_ONLY}). 287 */ 288 @GuardedBy("mLock") startSessionLocked(@onNull IBinder activityToken, int taskId, int uid, @NonNull IBinder appCallbackToken, @NonNull AutofillId autofillId, @NonNull Rect virtualBounds, @Nullable AutofillValue value, boolean hasCallback, @NonNull ComponentName componentName, boolean compatMode, boolean bindInstantServiceAllowed, int flags)289 long startSessionLocked(@NonNull IBinder activityToken, int taskId, int uid, 290 @NonNull IBinder appCallbackToken, @NonNull AutofillId autofillId, 291 @NonNull Rect virtualBounds, @Nullable AutofillValue value, boolean hasCallback, 292 @NonNull ComponentName componentName, boolean compatMode, 293 boolean bindInstantServiceAllowed, int flags) { 294 // FLAG_AUGMENTED_AUTOFILL_REQUEST is set in the flags when standard autofill is disabled 295 // but the package is whitelisted for augmented autofill 296 boolean forAugmentedAutofillOnly = (flags 297 & FLAG_ADD_CLIENT_ENABLED_FOR_AUGMENTED_AUTOFILL_ONLY) != 0; 298 if (!isEnabledLocked() && !forAugmentedAutofillOnly) { 299 return 0; 300 } 301 302 if (!forAugmentedAutofillOnly && isAutofillDisabledLocked(componentName)) { 303 // Standard autofill is enabled, but service disabled autofill for this activity; that 304 // means no session, unless the activity is whitelisted for augmented autofill 305 if (isWhitelistedForAugmentedAutofillLocked(componentName)) { 306 if (sDebug) { 307 Slog.d(TAG, "startSession(" + componentName + "): disabled by service but " 308 + "whitelisted for augmented autofill"); 309 } 310 forAugmentedAutofillOnly = true; 311 312 } else { 313 if (sDebug) { 314 Slog.d(TAG, "startSession(" + componentName + "): ignored because " 315 + "disabled by service and not whitelisted for augmented autofill"); 316 } 317 final IAutoFillManagerClient client = IAutoFillManagerClient.Stub 318 .asInterface(appCallbackToken); 319 try { 320 client.setSessionFinished(AutofillManager.STATE_DISABLED_BY_SERVICE, 321 /* autofillableIds= */ null); 322 } catch (RemoteException e) { 323 Slog.w(TAG, 324 "Could not notify " + componentName + " that it's disabled: " + e); 325 } 326 327 return NO_SESSION; 328 } 329 } 330 331 if (sVerbose) { 332 Slog.v(TAG, "startSession(): token=" + activityToken + ", flags=" + flags 333 + ", forAugmentedAutofillOnly=" + forAugmentedAutofillOnly); 334 } 335 336 // Occasionally clean up abandoned sessions 337 pruneAbandonedSessionsLocked(); 338 339 final Session newSession = createSessionByTokenLocked(activityToken, taskId, uid, 340 appCallbackToken, hasCallback, componentName, compatMode, 341 bindInstantServiceAllowed, forAugmentedAutofillOnly, flags); 342 if (newSession == null) { 343 return NO_SESSION; 344 } 345 346 // Service can be null when it's only for augmented autofill 347 String servicePackageName = mInfo == null ? null : mInfo.getServiceInfo().packageName; 348 final String historyItem = 349 "id=" + newSession.id + " uid=" + uid + " a=" + componentName.toShortString() 350 + " s=" + servicePackageName 351 + " u=" + mUserId + " i=" + autofillId + " b=" + virtualBounds 352 + " hc=" + hasCallback + " f=" + flags + " aa=" + forAugmentedAutofillOnly; 353 mMaster.logRequestLocked(historyItem); 354 355 newSession.updateLocked(autofillId, virtualBounds, value, ACTION_START_SESSION, flags); 356 357 if (forAugmentedAutofillOnly) { 358 // Must embed the flag in the response, at the high-end side of the long. 359 // (session is always positive, so we don't have to worry about the signal bit) 360 final long extraFlags = 361 ((long) RECEIVER_FLAG_SESSION_FOR_AUGMENTED_AUTOFILL_ONLY) << 32; 362 final long result = extraFlags | newSession.id; 363 return result; 364 } else { 365 return newSession.id; 366 } 367 } 368 369 /** 370 * Remove abandoned sessions if needed. 371 */ 372 @GuardedBy("mLock") pruneAbandonedSessionsLocked()373 private void pruneAbandonedSessionsLocked() { 374 long now = System.currentTimeMillis(); 375 if (mLastPrune < now - MAX_ABANDONED_SESSION_MILLIS) { 376 mLastPrune = now; 377 378 if (mSessions.size() > 0) { 379 (new PruneTask()).execute(); 380 } 381 } 382 } 383 384 @GuardedBy("mLock") setAutofillFailureLocked(int sessionId, int uid, @NonNull List<AutofillId> ids)385 void setAutofillFailureLocked(int sessionId, int uid, @NonNull List<AutofillId> ids) { 386 if (!isEnabledLocked()) { 387 return; 388 } 389 final Session session = mSessions.get(sessionId); 390 if (session == null || uid != session.uid) { 391 Slog.v(TAG, "setAutofillFailure(): no session for " + sessionId + "(" + uid + ")"); 392 return; 393 } 394 session.setAutofillFailureLocked(ids); 395 } 396 397 @GuardedBy("mLock") finishSessionLocked(int sessionId, int uid)398 void finishSessionLocked(int sessionId, int uid) { 399 if (!isEnabledLocked()) { 400 return; 401 } 402 403 final Session session = mSessions.get(sessionId); 404 if (session == null || uid != session.uid) { 405 if (sVerbose) { 406 Slog.v(TAG, "finishSessionLocked(): no session for " + sessionId + "(" + uid + ")"); 407 } 408 return; 409 } 410 411 session.logContextCommitted(); 412 413 final boolean finished = session.showSaveLocked(); 414 if (sVerbose) Slog.v(TAG, "finishSessionLocked(): session finished on save? " + finished); 415 416 if (finished) { 417 session.removeSelfLocked(); 418 } 419 } 420 421 @GuardedBy("mLock") cancelSessionLocked(int sessionId, int uid)422 void cancelSessionLocked(int sessionId, int uid) { 423 if (!isEnabledLocked()) { 424 return; 425 } 426 427 final Session session = mSessions.get(sessionId); 428 if (session == null || uid != session.uid) { 429 Slog.w(TAG, "cancelSessionLocked(): no session for " + sessionId + "(" + uid + ")"); 430 return; 431 } 432 session.removeSelfLocked(); 433 } 434 435 @GuardedBy("mLock") disableOwnedAutofillServicesLocked(int uid)436 void disableOwnedAutofillServicesLocked(int uid) { 437 Slog.i(TAG, "disableOwnedServices(" + uid + "): " + mInfo); 438 if (mInfo == null) return; 439 440 final ServiceInfo serviceInfo = mInfo.getServiceInfo(); 441 if (serviceInfo.applicationInfo.uid != uid) { 442 Slog.w(TAG, "disableOwnedServices(): ignored when called by UID " + uid 443 + " instead of " + serviceInfo.applicationInfo.uid 444 + " for service " + mInfo); 445 return; 446 } 447 448 449 final long identity = Binder.clearCallingIdentity(); 450 try { 451 final String autoFillService = getComponentNameLocked(); 452 final ComponentName componentName = serviceInfo.getComponentName(); 453 if (componentName.equals(ComponentName.unflattenFromString(autoFillService))) { 454 mMetricsLogger.action(MetricsEvent.AUTOFILL_SERVICE_DISABLED_SELF, 455 componentName.getPackageName()); 456 Settings.Secure.putStringForUser(getContext().getContentResolver(), 457 Settings.Secure.AUTOFILL_SERVICE, null, mUserId); 458 destroySessionsLocked(); 459 } else { 460 Slog.w(TAG, "disableOwnedServices(): ignored because current service (" 461 + serviceInfo + ") does not match Settings (" + autoFillService + ")"); 462 } 463 } finally { 464 Binder.restoreCallingIdentity(identity); 465 } 466 } 467 468 @GuardedBy("mLock") createSessionByTokenLocked(@onNull IBinder activityToken, int taskId, int uid, @NonNull IBinder appCallbackToken, boolean hasCallback, @NonNull ComponentName componentName, boolean compatMode, boolean bindInstantServiceAllowed, boolean forAugmentedAutofillOnly, int flags)469 private Session createSessionByTokenLocked(@NonNull IBinder activityToken, int taskId, int uid, 470 @NonNull IBinder appCallbackToken, boolean hasCallback, 471 @NonNull ComponentName componentName, boolean compatMode, 472 boolean bindInstantServiceAllowed, boolean forAugmentedAutofillOnly, 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 = Math.abs(sRandom.nextInt()); 484 } while (sessionId == 0 || sessionId == NO_SESSION 485 || mSessions.indexOfKey(sessionId) >= 0); 486 487 assertCallerLocked(componentName, compatMode); 488 489 // It's null when the session is just for augmented autofill 490 final ComponentName serviceComponentName = mInfo == null ? null 491 : mInfo.getServiceInfo().getComponentName(); 492 final Session newSession = new Session(this, mUi, getContext(), mHandler, mUserId, mLock, 493 sessionId, taskId, uid, activityToken, appCallbackToken, hasCallback, 494 mUiLatencyHistory, mWtfHistory, serviceComponentName, 495 componentName, compatMode, bindInstantServiceAllowed, forAugmentedAutofillOnly, 496 flags); 497 mSessions.put(newSession.id, newSession); 498 499 return newSession; 500 } 501 502 /** 503 * Asserts the component is owned by the caller. 504 */ assertCallerLocked(@onNull ComponentName componentName, boolean compatMode)505 private void assertCallerLocked(@NonNull ComponentName componentName, boolean compatMode) { 506 final String packageName = componentName.getPackageName(); 507 final PackageManager pm = getContext().getPackageManager(); 508 final int callingUid = Binder.getCallingUid(); 509 final int packageUid; 510 try { 511 packageUid = pm.getPackageUidAsUser(packageName, UserHandle.getCallingUserId()); 512 } catch (NameNotFoundException e) { 513 throw new SecurityException("Could not verify UID for " + componentName); 514 } 515 if (callingUid != packageUid && !LocalServices.getService(ActivityManagerInternal.class) 516 .hasRunningActivity(callingUid, packageName)) { 517 final String[] packages = pm.getPackagesForUid(callingUid); 518 final String callingPackage = packages != null ? packages[0] : "uid-" + callingUid; 519 Slog.w(TAG, "App (package=" + callingPackage + ", UID=" + callingUid 520 + ") passed component (" + componentName + ") owned by UID " + packageUid); 521 522 // NOTE: not using Helper.newLogMaker() because we don't have the session id 523 final LogMaker log = new LogMaker(MetricsEvent.AUTOFILL_FORGED_COMPONENT_ATTEMPT) 524 .setPackageName(callingPackage) 525 .addTaggedData(MetricsEvent.FIELD_AUTOFILL_SERVICE, getServicePackageName()) 526 .addTaggedData(MetricsEvent.FIELD_AUTOFILL_FORGED_COMPONENT_NAME, 527 componentName == null ? "null" : componentName.flattenToShortString()); 528 if (compatMode) { 529 log.addTaggedData(MetricsEvent.FIELD_AUTOFILL_COMPAT_MODE, 1); 530 } 531 mMetricsLogger.write(log); 532 533 throw new SecurityException("Invalid component: " + componentName); 534 } 535 } 536 537 /** 538 * Restores a session after an activity was temporarily destroyed. 539 * 540 * @param sessionId The id of the session to restore 541 * @param uid UID of the process that tries to restore the session 542 * @param activityToken The new instance of the activity 543 * @param appCallback The callbacks to the activity 544 */ restoreSession(int sessionId, int uid, @NonNull IBinder activityToken, @NonNull IBinder appCallback)545 boolean restoreSession(int sessionId, int uid, @NonNull IBinder activityToken, 546 @NonNull IBinder appCallback) { 547 final Session session = mSessions.get(sessionId); 548 549 if (session == null || uid != session.uid) { 550 return false; 551 } else { 552 session.switchActivity(activityToken, appCallback); 553 return true; 554 } 555 } 556 557 /** 558 * Updates a session and returns whether it should be restarted. 559 */ 560 @GuardedBy("mLock") updateSessionLocked(int sessionId, int uid, AutofillId autofillId, Rect virtualBounds, AutofillValue value, int action, int flags)561 boolean updateSessionLocked(int sessionId, int uid, AutofillId autofillId, Rect virtualBounds, 562 AutofillValue value, int action, int flags) { 563 final Session session = mSessions.get(sessionId); 564 if (session == null || session.uid != uid) { 565 if ((flags & FLAG_MANUAL_REQUEST) != 0) { 566 if (sDebug) { 567 Slog.d(TAG, "restarting session " + sessionId + " due to manual request on " 568 + autofillId); 569 } 570 return true; 571 } 572 if (sVerbose) { 573 Slog.v(TAG, "updateSessionLocked(): session gone for " + sessionId 574 + "(" + uid + ")"); 575 } 576 return false; 577 } 578 579 session.updateLocked(autofillId, virtualBounds, value, action, flags); 580 return false; 581 } 582 583 @GuardedBy("mLock") removeSessionLocked(int sessionId)584 void removeSessionLocked(int sessionId) { 585 mSessions.remove(sessionId); 586 } 587 588 /** 589 * Ges the previous sessions asked to be kept alive in a given activity task. 590 * 591 * @param session session calling this method (so it's excluded from the result). 592 */ 593 @Nullable 594 @GuardedBy("mLock") getPreviousSessionsLocked(@onNull Session session)595 ArrayList<Session> getPreviousSessionsLocked(@NonNull Session session) { 596 final int size = mSessions.size(); 597 ArrayList<Session> previousSessions = null; 598 for (int i = 0; i < size; i++) { 599 final Session previousSession = mSessions.valueAt(i); 600 if (previousSession.taskId == session.taskId && previousSession.id != session.id 601 && (previousSession.getSaveInfoFlagsLocked() & SaveInfo.FLAG_DELAY_SAVE) != 0) { 602 if (previousSessions == null) { 603 previousSessions = new ArrayList<>(size); 604 } 605 previousSessions.add(previousSession); 606 } 607 } 608 // TODO(b/113281366): remove returned sessions / add CTS test 609 return previousSessions; 610 } 611 handleSessionSave(Session session)612 void handleSessionSave(Session session) { 613 synchronized (mLock) { 614 if (mSessions.get(session.id) == null) { 615 Slog.w(TAG, "handleSessionSave(): already gone: " + session.id); 616 617 return; 618 } 619 session.callSaveLocked(); 620 } 621 } 622 onPendingSaveUi(int operation, @NonNull IBinder token)623 void onPendingSaveUi(int operation, @NonNull IBinder token) { 624 if (sVerbose) Slog.v(TAG, "onPendingSaveUi(" + operation + "): " + token); 625 synchronized (mLock) { 626 final int sessionCount = mSessions.size(); 627 for (int i = sessionCount - 1; i >= 0; i--) { 628 final Session session = mSessions.valueAt(i); 629 if (session.isSaveUiPendingForTokenLocked(token)) { 630 session.onPendingSaveUi(operation, token); 631 return; 632 } 633 } 634 } 635 if (sDebug) { 636 Slog.d(TAG, "No pending Save UI for token " + token + " and operation " 637 + DebugUtils.flagsToString(AutofillManager.class, "PENDING_UI_OPERATION_", 638 operation)); 639 } 640 } 641 642 @GuardedBy("mLock") 643 @Override // from PerUserSystemService handlePackageUpdateLocked(@onNull String packageName)644 protected void handlePackageUpdateLocked(@NonNull String packageName) { 645 final ServiceInfo serviceInfo = mFieldClassificationStrategy.getServiceInfo(); 646 if (serviceInfo != null && serviceInfo.packageName.equals(packageName)) { 647 resetExtServiceLocked(); 648 } 649 } 650 651 @GuardedBy("mLock") resetExtServiceLocked()652 void resetExtServiceLocked() { 653 if (sVerbose) Slog.v(TAG, "reset autofill service."); 654 mFieldClassificationStrategy.reset(); 655 } 656 657 @GuardedBy("mLock") destroyLocked()658 void destroyLocked() { 659 if (sVerbose) Slog.v(TAG, "destroyLocked()"); 660 661 resetExtServiceLocked(); 662 663 final int numSessions = mSessions.size(); 664 final ArraySet<RemoteFillService> remoteFillServices = new ArraySet<>(numSessions); 665 for (int i = 0; i < numSessions; i++) { 666 final RemoteFillService remoteFillService = mSessions.valueAt(i).destroyLocked(); 667 if (remoteFillService != null) { 668 remoteFillServices.add(remoteFillService); 669 } 670 } 671 mSessions.clear(); 672 for (int i = 0; i < remoteFillServices.size(); i++) { 673 remoteFillServices.valueAt(i).destroy(); 674 } 675 676 sendStateToClients(/* resetclient=*/ true); 677 if (mClients != null) { 678 mClients.kill(); 679 mClients = null; 680 } 681 } 682 683 /** 684 * Initializes the last fill selection after an autofill service returned a new 685 * {@link FillResponse}. 686 */ setLastResponse(int sessionId, @NonNull FillResponse response)687 void setLastResponse(int sessionId, @NonNull FillResponse response) { 688 synchronized (mLock) { 689 mEventHistory = new FillEventHistory(sessionId, response.getClientState()); 690 } 691 } 692 693 /** 694 * Resets the last fill selection. 695 */ resetLastResponse()696 void resetLastResponse() { 697 synchronized (mLock) { 698 mEventHistory = null; 699 } 700 } 701 702 @GuardedBy("mLock") isValidEventLocked(String method, int sessionId)703 private boolean isValidEventLocked(String method, int sessionId) { 704 if (mEventHistory == null) { 705 Slog.w(TAG, method + ": not logging event because history is null"); 706 return false; 707 } 708 if (sessionId != mEventHistory.getSessionId()) { 709 if (sDebug) { 710 Slog.d(TAG, method + ": not logging event for session " + sessionId 711 + " because tracked session is " + mEventHistory.getSessionId()); 712 } 713 return false; 714 } 715 return true; 716 } 717 718 /** 719 * Updates the last fill selection when an authentication was selected. 720 */ setAuthenticationSelected(int sessionId, @Nullable Bundle clientState)721 void setAuthenticationSelected(int sessionId, @Nullable Bundle clientState) { 722 synchronized (mLock) { 723 if (isValidEventLocked("setAuthenticationSelected()", sessionId)) { 724 mEventHistory.addEvent( 725 new Event(Event.TYPE_AUTHENTICATION_SELECTED, null, clientState, null, null, 726 null, null, null, null, null, null)); 727 } 728 } 729 } 730 731 /** 732 * Updates the last fill selection when an dataset authentication was selected. 733 */ logDatasetAuthenticationSelected(@ullable String selectedDataset, int sessionId, @Nullable Bundle clientState)734 void logDatasetAuthenticationSelected(@Nullable String selectedDataset, int sessionId, 735 @Nullable Bundle clientState) { 736 synchronized (mLock) { 737 if (isValidEventLocked("logDatasetAuthenticationSelected()", sessionId)) { 738 mEventHistory.addEvent( 739 new Event(Event.TYPE_DATASET_AUTHENTICATION_SELECTED, selectedDataset, 740 clientState, null, null, null, null, null, null, null, null)); 741 } 742 } 743 } 744 745 /** 746 * Updates the last fill selection when an save Ui is shown. 747 */ logSaveShown(int sessionId, @Nullable Bundle clientState)748 void logSaveShown(int sessionId, @Nullable Bundle clientState) { 749 synchronized (mLock) { 750 if (isValidEventLocked("logSaveShown()", sessionId)) { 751 mEventHistory.addEvent(new Event(Event.TYPE_SAVE_SHOWN, null, clientState, null, 752 null, null, null, null, null, null, null)); 753 } 754 } 755 } 756 757 /** 758 * Updates the last fill response when a dataset was selected. 759 */ logDatasetSelected(@ullable String selectedDataset, int sessionId, @Nullable Bundle clientState)760 void logDatasetSelected(@Nullable String selectedDataset, int sessionId, 761 @Nullable Bundle clientState) { 762 synchronized (mLock) { 763 if (isValidEventLocked("logDatasetSelected()", sessionId)) { 764 mEventHistory.addEvent( 765 new Event(Event.TYPE_DATASET_SELECTED, selectedDataset, clientState, null, 766 null, null, null, null, null, null, null)); 767 } 768 } 769 } 770 771 /** 772 * Updates the last fill response when an autofill context is committed. 773 */ 774 @GuardedBy("mLock") logContextCommittedLocked(int sessionId, @Nullable Bundle clientState, @Nullable ArrayList<String> selectedDatasets, @Nullable ArraySet<String> ignoredDatasets, @Nullable ArrayList<AutofillId> changedFieldIds, @Nullable ArrayList<String> changedDatasetIds, @Nullable ArrayList<AutofillId> manuallyFilledFieldIds, @Nullable ArrayList<ArrayList<String>> manuallyFilledDatasetIds, @NonNull ComponentName appComponentName, boolean compatMode)775 void logContextCommittedLocked(int sessionId, @Nullable Bundle clientState, 776 @Nullable ArrayList<String> selectedDatasets, 777 @Nullable ArraySet<String> ignoredDatasets, 778 @Nullable ArrayList<AutofillId> changedFieldIds, 779 @Nullable ArrayList<String> changedDatasetIds, 780 @Nullable ArrayList<AutofillId> manuallyFilledFieldIds, 781 @Nullable ArrayList<ArrayList<String>> manuallyFilledDatasetIds, 782 @NonNull ComponentName appComponentName, boolean compatMode) { 783 logContextCommittedLocked(sessionId, clientState, selectedDatasets, ignoredDatasets, 784 changedFieldIds, changedDatasetIds, manuallyFilledFieldIds, 785 manuallyFilledDatasetIds, null, null, appComponentName, compatMode); 786 } 787 788 @GuardedBy("mLock") logContextCommittedLocked(int sessionId, @Nullable Bundle clientState, @Nullable ArrayList<String> selectedDatasets, @Nullable ArraySet<String> ignoredDatasets, @Nullable ArrayList<AutofillId> changedFieldIds, @Nullable ArrayList<String> changedDatasetIds, @Nullable ArrayList<AutofillId> manuallyFilledFieldIds, @Nullable ArrayList<ArrayList<String>> manuallyFilledDatasetIds, @Nullable ArrayList<AutofillId> detectedFieldIdsList, @Nullable ArrayList<FieldClassification> detectedFieldClassificationsList, @NonNull ComponentName appComponentName, boolean compatMode)789 void logContextCommittedLocked(int sessionId, @Nullable Bundle clientState, 790 @Nullable ArrayList<String> selectedDatasets, 791 @Nullable ArraySet<String> ignoredDatasets, 792 @Nullable ArrayList<AutofillId> changedFieldIds, 793 @Nullable ArrayList<String> changedDatasetIds, 794 @Nullable ArrayList<AutofillId> manuallyFilledFieldIds, 795 @Nullable ArrayList<ArrayList<String>> manuallyFilledDatasetIds, 796 @Nullable ArrayList<AutofillId> detectedFieldIdsList, 797 @Nullable ArrayList<FieldClassification> detectedFieldClassificationsList, 798 @NonNull ComponentName appComponentName, boolean compatMode) { 799 if (isValidEventLocked("logDatasetNotSelected()", sessionId)) { 800 if (sVerbose) { 801 Slog.v(TAG, "logContextCommitted() with FieldClassification: id=" + sessionId 802 + ", selectedDatasets=" + selectedDatasets 803 + ", ignoredDatasetIds=" + ignoredDatasets 804 + ", changedAutofillIds=" + changedFieldIds 805 + ", changedDatasetIds=" + changedDatasetIds 806 + ", manuallyFilledFieldIds=" + manuallyFilledFieldIds 807 + ", detectedFieldIds=" + detectedFieldIdsList 808 + ", detectedFieldClassifications=" + detectedFieldClassificationsList 809 + ", appComponentName=" + appComponentName.toShortString() 810 + ", compatMode=" + compatMode); 811 } 812 AutofillId[] detectedFieldsIds = null; 813 FieldClassification[] detectedFieldClassifications = null; 814 if (detectedFieldIdsList != null) { 815 detectedFieldsIds = new AutofillId[detectedFieldIdsList.size()]; 816 detectedFieldIdsList.toArray(detectedFieldsIds); 817 detectedFieldClassifications = 818 new FieldClassification[detectedFieldClassificationsList.size()]; 819 detectedFieldClassificationsList.toArray(detectedFieldClassifications); 820 821 final int numberFields = detectedFieldsIds.length; 822 int totalSize = 0; 823 float totalScore = 0; 824 for (int i = 0; i < numberFields; i++) { 825 final FieldClassification fc = detectedFieldClassifications[i]; 826 final List<Match> matches = fc.getMatches(); 827 final int size = matches.size(); 828 totalSize += size; 829 for (int j = 0; j < size; j++) { 830 totalScore += matches.get(j).getScore(); 831 } 832 } 833 834 final int averageScore = (int) ((totalScore * 100) / totalSize); 835 mMetricsLogger.write(Helper 836 .newLogMaker(MetricsEvent.AUTOFILL_FIELD_CLASSIFICATION_MATCHES, 837 appComponentName, getServicePackageName(), sessionId, compatMode) 838 .setCounterValue(numberFields) 839 .addTaggedData(MetricsEvent.FIELD_AUTOFILL_MATCH_SCORE, 840 averageScore)); 841 } 842 mEventHistory.addEvent(new Event(Event.TYPE_CONTEXT_COMMITTED, null, 843 clientState, selectedDatasets, ignoredDatasets, 844 changedFieldIds, changedDatasetIds, 845 manuallyFilledFieldIds, manuallyFilledDatasetIds, 846 detectedFieldsIds, detectedFieldClassifications)); 847 } 848 } 849 850 /** 851 * Gets the fill event history. 852 * 853 * @param callingUid The calling uid 854 * 855 * @return The history or {@code null} if there is none. 856 */ getFillEventHistory(int callingUid)857 FillEventHistory getFillEventHistory(int callingUid) { 858 synchronized (mLock) { 859 if (mEventHistory != null 860 && isCalledByServiceLocked("getFillEventHistory", callingUid)) { 861 return mEventHistory; 862 } 863 } 864 return null; 865 } 866 867 // Called by Session - does not need to check uid getUserData()868 UserData getUserData() { 869 synchronized (mLock) { 870 return mUserData; 871 } 872 } 873 874 // Called by AutofillManager getUserData(int callingUid)875 UserData getUserData(int callingUid) { 876 synchronized (mLock) { 877 if (isCalledByServiceLocked("getUserData", callingUid)) { 878 return mUserData; 879 } 880 } 881 return null; 882 } 883 884 // Called by AutofillManager setUserData(int callingUid, UserData userData)885 void setUserData(int callingUid, UserData userData) { 886 synchronized (mLock) { 887 if (!isCalledByServiceLocked("setUserData", callingUid)) { 888 return; 889 } 890 mUserData = userData; 891 // Log it 892 final int numberFields = mUserData == null ? 0: mUserData.getCategoryIds().length; 893 // NOTE: contrary to most metrics, the service name is logged as the main package name 894 // here, not as MetricsEvent.FIELD_AUTOFILL_SERVICE 895 mMetricsLogger.write(new LogMaker(MetricsEvent.AUTOFILL_USERDATA_UPDATED) 896 .setPackageName(getServicePackageName()) 897 .addTaggedData(MetricsEvent.FIELD_AUTOFILL_NUM_VALUES, numberFields)); 898 } 899 } 900 901 @GuardedBy("mLock") isCalledByServiceLocked(@onNull String methodName, int callingUid)902 private boolean isCalledByServiceLocked(@NonNull String methodName, int callingUid) { 903 final int serviceUid = getServiceUidLocked(); 904 if (serviceUid != callingUid) { 905 Slog.w(TAG, methodName + "() called by UID " + callingUid 906 + ", but service UID is " + serviceUid); 907 return false; 908 } 909 return true; 910 } 911 912 @GuardedBy("mLock") getSupportedSmartSuggestionModesLocked()913 @SmartSuggestionMode int getSupportedSmartSuggestionModesLocked() { 914 return mMaster.getSupportedSmartSuggestionModesLocked(); 915 } 916 917 @Override 918 @GuardedBy("mLock") dumpLocked(String prefix, PrintWriter pw)919 protected void dumpLocked(String prefix, PrintWriter pw) { 920 super.dumpLocked(prefix, pw); 921 922 final String prefix2 = prefix + " "; 923 924 pw.print(prefix); pw.print("UID: "); pw.println(getServiceUidLocked()); 925 pw.print(prefix); pw.print("Autofill Service Info: "); 926 if (mInfo == null) { 927 pw.println("N/A"); 928 } else { 929 pw.println(); 930 mInfo.dump(prefix2, pw); 931 } 932 pw.print(prefix); pw.print("Default component: "); pw.println(getContext() 933 .getString(R.string.config_defaultAutofillService)); 934 935 pw.print(prefix); pw.println("mAugmentedAutofillNamer: "); 936 pw.print(prefix2); mMaster.mAugmentedAutofillResolver.dumpShort(pw, mUserId); pw.println(); 937 938 if (mRemoteAugmentedAutofillService != null) { 939 pw.print(prefix); pw.println("RemoteAugmentedAutofillService: "); 940 mRemoteAugmentedAutofillService.dump(prefix2, pw); 941 } 942 if (mRemoteAugmentedAutofillServiceInfo != null) { 943 pw.print(prefix); pw.print("RemoteAugmentedAutofillServiceInfo: "); 944 pw.println(mRemoteAugmentedAutofillServiceInfo); 945 } 946 947 pw.print(prefix); pw.print("Field classification enabled: "); 948 pw.println(isFieldClassificationEnabledLocked()); 949 pw.print(prefix); pw.print("Compat pkgs: "); 950 final ArrayMap<String, Long> compatPkgs = getCompatibilityPackagesLocked(); 951 if (compatPkgs == null) { 952 pw.println("N/A"); 953 } else { 954 pw.println(compatPkgs); 955 } 956 pw.print(prefix); pw.print("Last prune: "); pw.println(mLastPrune); 957 958 pw.print(prefix); pw.print("Disabled apps: "); 959 960 if (mDisabledApps == null) { 961 pw.println("N/A"); 962 } else { 963 final int size = mDisabledApps.size(); 964 pw.println(size); 965 final StringBuilder builder = new StringBuilder(); 966 final long now = SystemClock.elapsedRealtime(); 967 for (int i = 0; i < size; i++) { 968 final String packageName = mDisabledApps.keyAt(i); 969 final long expiration = mDisabledApps.valueAt(i); 970 builder.append(prefix).append(prefix) 971 .append(i).append(". ").append(packageName).append(": "); 972 TimeUtils.formatDuration((expiration - now), builder); 973 builder.append('\n'); 974 } 975 pw.println(builder); 976 } 977 978 pw.print(prefix); pw.print("Disabled activities: "); 979 980 if (mDisabledActivities == null) { 981 pw.println("N/A"); 982 } else { 983 final int size = mDisabledActivities.size(); 984 pw.println(size); 985 final StringBuilder builder = new StringBuilder(); 986 final long now = SystemClock.elapsedRealtime(); 987 for (int i = 0; i < size; i++) { 988 final ComponentName component = mDisabledActivities.keyAt(i); 989 final long expiration = mDisabledActivities.valueAt(i); 990 builder.append(prefix).append(prefix) 991 .append(i).append(". ").append(component).append(": "); 992 TimeUtils.formatDuration((expiration - now), builder); 993 builder.append('\n'); 994 } 995 pw.println(builder); 996 } 997 998 final int size = mSessions.size(); 999 if (size == 0) { 1000 pw.print(prefix); pw.println("No sessions"); 1001 } else { 1002 pw.print(prefix); pw.print(size); pw.println(" sessions:"); 1003 for (int i = 0; i < size; i++) { 1004 pw.print(prefix); pw.print("#"); pw.println(i + 1); 1005 mSessions.valueAt(i).dumpLocked(prefix2, pw); 1006 } 1007 } 1008 1009 pw.print(prefix); pw.print("Clients: "); 1010 if (mClients == null) { 1011 pw.println("N/A"); 1012 } else { 1013 pw.println(); 1014 mClients.dump(pw, prefix2); 1015 } 1016 1017 if (mEventHistory == null || mEventHistory.getEvents() == null 1018 || mEventHistory.getEvents().size() == 0) { 1019 pw.print(prefix); pw.println("No event on last fill response"); 1020 } else { 1021 pw.print(prefix); pw.println("Events of last fill response:"); 1022 pw.print(prefix); 1023 1024 int numEvents = mEventHistory.getEvents().size(); 1025 for (int i = 0; i < numEvents; i++) { 1026 final Event event = mEventHistory.getEvents().get(i); 1027 pw.println(" " + i + ": eventType=" + event.getType() + " datasetId=" 1028 + event.getDatasetId()); 1029 } 1030 } 1031 1032 pw.print(prefix); pw.print("User data: "); 1033 if (mUserData == null) { 1034 pw.println("N/A"); 1035 } else { 1036 pw.println(); 1037 mUserData.dump(prefix2, pw); 1038 } 1039 1040 pw.print(prefix); pw.println("Field Classification strategy: "); 1041 mFieldClassificationStrategy.dump(prefix2, pw); 1042 } 1043 1044 @GuardedBy("mLock") destroySessionsLocked()1045 void destroySessionsLocked() { 1046 if (mSessions.size() == 0) { 1047 mUi.destroyAll(null, null, false); 1048 return; 1049 } 1050 while (mSessions.size() > 0) { 1051 mSessions.valueAt(0).forceRemoveSelfLocked(); 1052 } 1053 } 1054 1055 @GuardedBy("mLock") destroySessionsForAugmentedAutofillOnlyLocked()1056 void destroySessionsForAugmentedAutofillOnlyLocked() { 1057 final int sessionCount = mSessions.size(); 1058 for (int i = sessionCount - 1; i >= 0; i--) { 1059 mSessions.valueAt(i).forceRemoveSelfIfForAugmentedAutofillOnlyLocked(); 1060 } 1061 } 1062 1063 // TODO(b/64940307): remove this method if SaveUI is refactored to be attached on activities 1064 @GuardedBy("mLock") destroyFinishedSessionsLocked()1065 void destroyFinishedSessionsLocked() { 1066 final int sessionCount = mSessions.size(); 1067 for (int i = sessionCount - 1; i >= 0; i--) { 1068 final Session session = mSessions.valueAt(i); 1069 if (session.isSavingLocked()) { 1070 if (sDebug) Slog.d(TAG, "destroyFinishedSessionsLocked(): " + session.id); 1071 session.forceRemoveSelfLocked(); 1072 } 1073 else { 1074 session.destroyAugmentedAutofillWindowsLocked(); 1075 } 1076 } 1077 } 1078 1079 @GuardedBy("mLock") listSessionsLocked(ArrayList<String> output)1080 void listSessionsLocked(ArrayList<String> output) { 1081 final int numSessions = mSessions.size(); 1082 if (numSessions <= 0) return; 1083 1084 final String fmt = "%d:%s:%s"; 1085 for (int i = 0; i < numSessions; i++) { 1086 final int id = mSessions.keyAt(i); 1087 final String service = mInfo == null 1088 ? "no_svc" 1089 : mInfo.getServiceInfo().getComponentName().flattenToShortString(); 1090 final String augmentedService = mRemoteAugmentedAutofillServiceInfo == null 1091 ? "no_aug" 1092 : mRemoteAugmentedAutofillServiceInfo.getComponentName().flattenToShortString(); 1093 output.add(String.format(fmt, id, service, augmentedService)); 1094 } 1095 } 1096 1097 @GuardedBy("mLock") getCompatibilityPackagesLocked()1098 @Nullable ArrayMap<String, Long> getCompatibilityPackagesLocked() { 1099 if (mInfo != null) { 1100 return mInfo.getCompatibilityPackages(); 1101 } 1102 return null; 1103 } 1104 1105 @GuardedBy("mLock") getRemoteAugmentedAutofillServiceLocked()1106 @Nullable RemoteAugmentedAutofillService getRemoteAugmentedAutofillServiceLocked() { 1107 if (mRemoteAugmentedAutofillService == null) { 1108 final String serviceName = mMaster.mAugmentedAutofillResolver.getServiceName(mUserId); 1109 if (serviceName == null) { 1110 if (mMaster.verbose) { 1111 Slog.v(TAG, "getRemoteAugmentedAutofillServiceLocked(): not set"); 1112 } 1113 return null; 1114 } 1115 final Pair<ServiceInfo, ComponentName> pair = RemoteAugmentedAutofillService 1116 .getComponentName(serviceName, mUserId, 1117 mMaster.mAugmentedAutofillResolver.isTemporary(mUserId)); 1118 if (pair == null) return null; 1119 1120 mRemoteAugmentedAutofillServiceInfo = pair.first; 1121 final ComponentName componentName = pair.second; 1122 if (sVerbose) { 1123 Slog.v(TAG, "getRemoteAugmentedAutofillServiceLocked(): " + componentName); 1124 } 1125 1126 mRemoteAugmentedAutofillService = new RemoteAugmentedAutofillService(getContext(), 1127 componentName, mUserId, new RemoteAugmentedAutofillServiceCallbacks() { 1128 @Override 1129 public void onServiceDied(@NonNull RemoteAugmentedAutofillService service) { 1130 Slog.w(TAG, "remote augmented autofill service died"); 1131 final RemoteAugmentedAutofillService remoteService = 1132 mRemoteAugmentedAutofillService; 1133 if (remoteService != null) { 1134 remoteService.destroy(); 1135 } 1136 mRemoteAugmentedAutofillService = null; 1137 } 1138 }, mMaster.isInstantServiceAllowed(), mMaster.verbose, 1139 mMaster.mAugmentedServiceIdleUnbindTimeoutMs, 1140 mMaster.mAugmentedServiceRequestTimeoutMs); 1141 } 1142 1143 return mRemoteAugmentedAutofillService; 1144 } 1145 1146 /** 1147 * Called when the {@link AutofillManagerService#mAugmentedAutofillResolver} 1148 * changed (among other places). 1149 */ updateRemoteAugmentedAutofillService()1150 void updateRemoteAugmentedAutofillService() { 1151 synchronized (mLock) { 1152 if (mRemoteAugmentedAutofillService != null) { 1153 if (sVerbose) { 1154 Slog.v(TAG, "updateRemoteAugmentedAutofillService(): " 1155 + "destroying old remote service"); 1156 } 1157 destroySessionsForAugmentedAutofillOnlyLocked(); 1158 mRemoteAugmentedAutofillService.destroy(); 1159 mRemoteAugmentedAutofillService = null; 1160 mRemoteAugmentedAutofillServiceInfo = null; 1161 resetAugmentedAutofillWhitelistLocked(); 1162 } 1163 1164 final boolean available = isAugmentedAutofillServiceAvailableLocked(); 1165 if (sVerbose) Slog.v(TAG, "updateRemoteAugmentedAutofillService(): " + available); 1166 1167 if (available) { 1168 mRemoteAugmentedAutofillService = getRemoteAugmentedAutofillServiceLocked(); 1169 } 1170 } 1171 } 1172 isAugmentedAutofillServiceAvailableLocked()1173 private boolean isAugmentedAutofillServiceAvailableLocked() { 1174 if (mMaster.verbose) { 1175 Slog.v(TAG, "isAugmentedAutofillService(): " 1176 + "setupCompleted=" + isSetupCompletedLocked() 1177 + ", disabled=" + isDisabledByUserRestrictionsLocked() 1178 + ", augmentedService=" 1179 + mMaster.mAugmentedAutofillResolver.getServiceName(mUserId)); 1180 } 1181 if (!isSetupCompletedLocked() || isDisabledByUserRestrictionsLocked() 1182 || mMaster.mAugmentedAutofillResolver.getServiceName(mUserId) == null) { 1183 return false; 1184 } 1185 return true; 1186 } 1187 isAugmentedAutofillServiceForUserLocked(int callingUid)1188 boolean isAugmentedAutofillServiceForUserLocked(int callingUid) { 1189 return mRemoteAugmentedAutofillServiceInfo != null 1190 && mRemoteAugmentedAutofillServiceInfo.applicationInfo.uid == callingUid; 1191 } 1192 1193 /** 1194 * Sets which packages and activities can trigger augmented autofill. 1195 * 1196 * @return whether caller UID is the augmented autofill service for the user 1197 */ 1198 @GuardedBy("mLock") setAugmentedAutofillWhitelistLocked(@ullable List<String> packages, @Nullable List<ComponentName> activities, int callingUid)1199 boolean setAugmentedAutofillWhitelistLocked(@Nullable List<String> packages, 1200 @Nullable List<ComponentName> activities, int callingUid) { 1201 1202 if (!isCalledByAugmentedAutofillServiceLocked("setAugmentedAutofillWhitelistLocked", 1203 callingUid)) { 1204 return false; 1205 } 1206 if (mMaster.verbose) { 1207 Slog.v(TAG, "setAugmentedAutofillWhitelistLocked(packages=" + packages + ", activities=" 1208 + activities + ")"); 1209 } 1210 whitelistForAugmentedAutofillPackages(packages, activities); 1211 final String serviceName; 1212 if (mRemoteAugmentedAutofillServiceInfo != null) { 1213 serviceName = mRemoteAugmentedAutofillServiceInfo.getComponentName() 1214 .flattenToShortString(); 1215 } else { 1216 Slog.e(TAG, "setAugmentedAutofillWhitelistLocked(): no service"); 1217 serviceName = "N/A"; 1218 } 1219 1220 final LogMaker log = new LogMaker(MetricsEvent.AUTOFILL_AUGMENTED_WHITELIST_REQUEST) 1221 .addTaggedData(MetricsEvent.FIELD_AUTOFILL_SERVICE, serviceName); 1222 if (packages != null) { 1223 log.addTaggedData(MetricsEvent.FIELD_AUTOFILL_NUMBER_PACKAGES, packages.size()); 1224 } 1225 if (activities != null) { 1226 log.addTaggedData(MetricsEvent.FIELD_AUTOFILL_NUMBER_ACTIVITIES, activities.size()); 1227 } 1228 mMetricsLogger.write(log); 1229 1230 return true; 1231 } 1232 1233 @GuardedBy("mLock") isCalledByAugmentedAutofillServiceLocked(@onNull String methodName, int callingUid)1234 private boolean isCalledByAugmentedAutofillServiceLocked(@NonNull String methodName, 1235 int callingUid) { 1236 // Lazy load service first 1237 final RemoteAugmentedAutofillService service = getRemoteAugmentedAutofillServiceLocked(); 1238 if (service == null) { 1239 Slog.w(TAG, methodName + "() called by UID " + callingUid 1240 + ", but there is no augmented autofill service defined for user " 1241 + getUserId()); 1242 return false; 1243 } 1244 1245 if (getAugmentedAutofillServiceUidLocked() != callingUid) { 1246 Slog.w(TAG, methodName + "() called by UID " + callingUid 1247 + ", but service UID is " + getAugmentedAutofillServiceUidLocked() 1248 + " for user " + getUserId()); 1249 return false; 1250 } 1251 return true; 1252 } 1253 1254 @GuardedBy("mLock") getAugmentedAutofillServiceUidLocked()1255 private int getAugmentedAutofillServiceUidLocked() { 1256 if (mRemoteAugmentedAutofillServiceInfo == null) { 1257 if (mMaster.verbose) { 1258 Slog.v(TAG, "getAugmentedAutofillServiceUid(): " 1259 + "no mRemoteAugmentedAutofillServiceInfo"); 1260 } 1261 return Process.INVALID_UID; 1262 } 1263 return mRemoteAugmentedAutofillServiceInfo.applicationInfo.uid; 1264 } 1265 1266 @GuardedBy("mLock") isWhitelistedForAugmentedAutofillLocked(@onNull ComponentName componentName)1267 boolean isWhitelistedForAugmentedAutofillLocked(@NonNull ComponentName componentName) { 1268 return mMaster.mAugmentedAutofillState.isWhitelisted(mUserId, componentName); 1269 } 1270 1271 /** 1272 * @throws IllegalArgumentException if packages or components are empty. 1273 */ whitelistForAugmentedAutofillPackages(@ullable List<String> packages, @Nullable List<ComponentName> components)1274 private void whitelistForAugmentedAutofillPackages(@Nullable List<String> packages, 1275 @Nullable List<ComponentName> components) { 1276 // TODO(b/123100824): add CTS test for when it's null 1277 synchronized (mLock) { 1278 if (mMaster.verbose) { 1279 Slog.v(TAG, "whitelisting packages: " + packages + "and activities: " + components); 1280 } 1281 mMaster.mAugmentedAutofillState.setWhitelist(mUserId, packages, components); 1282 } 1283 } 1284 1285 /** 1286 * Resets the augmented autofill whitelist. 1287 */ 1288 @GuardedBy("mLock") resetAugmentedAutofillWhitelistLocked()1289 void resetAugmentedAutofillWhitelistLocked() { 1290 if (mMaster.verbose) { 1291 Slog.v(TAG, "resetting augmented autofill whitelist"); 1292 } 1293 mMaster.mAugmentedAutofillState.resetWhitelist(mUserId); 1294 } 1295 sendStateToClients(boolean resetClient)1296 private void sendStateToClients(boolean resetClient) { 1297 final RemoteCallbackList<IAutoFillManagerClient> clients; 1298 final int userClientCount; 1299 synchronized (mLock) { 1300 if (mClients == null) { 1301 return; 1302 } 1303 clients = mClients; 1304 userClientCount = clients.beginBroadcast(); 1305 } 1306 try { 1307 for (int i = 0; i < userClientCount; i++) { 1308 final IAutoFillManagerClient client = clients.getBroadcastItem(i); 1309 try { 1310 final boolean resetSession; 1311 final boolean isEnabled; 1312 synchronized (mLock) { 1313 resetSession = resetClient || isClientSessionDestroyedLocked(client); 1314 isEnabled = isEnabledLocked(); 1315 } 1316 int flags = 0; 1317 if (isEnabled) { 1318 flags |= AutofillManager.SET_STATE_FLAG_ENABLED; 1319 } 1320 if (resetSession) { 1321 flags |= AutofillManager.SET_STATE_FLAG_RESET_SESSION; 1322 } 1323 if (resetClient) { 1324 flags |= AutofillManager.SET_STATE_FLAG_RESET_CLIENT; 1325 } 1326 if (sDebug) { 1327 flags |= AutofillManager.SET_STATE_FLAG_DEBUG; 1328 } 1329 if (sVerbose) { 1330 flags |= AutofillManager.SET_STATE_FLAG_VERBOSE; 1331 } 1332 client.setState(flags); 1333 } catch (RemoteException re) { 1334 /* ignore */ 1335 } 1336 } 1337 } finally { 1338 clients.finishBroadcast(); 1339 } 1340 } 1341 1342 @GuardedBy("mLock") isClientSessionDestroyedLocked(IAutoFillManagerClient client)1343 private boolean isClientSessionDestroyedLocked(IAutoFillManagerClient client) { 1344 final int sessionCount = mSessions.size(); 1345 for (int i = 0; i < sessionCount; i++) { 1346 final Session session = mSessions.valueAt(i); 1347 if (session.getClient().equals(client)) { 1348 return session.isDestroyed(); 1349 } 1350 } 1351 return true; 1352 } 1353 1354 /** 1355 * Called by {@link Session} when service asked to disable autofill for an app. 1356 */ disableAutofillForApp(@onNull String packageName, long duration, int sessionId, boolean compatMode)1357 void disableAutofillForApp(@NonNull String packageName, long duration, int sessionId, 1358 boolean compatMode) { 1359 synchronized (mLock) { 1360 if (mDisabledApps == null) { 1361 mDisabledApps = new ArrayMap<>(1); 1362 } 1363 long expiration = SystemClock.elapsedRealtime() + duration; 1364 // Protect it against overflow 1365 if (expiration < 0) { 1366 expiration = Long.MAX_VALUE; 1367 } 1368 mDisabledApps.put(packageName, expiration); 1369 int intDuration = duration > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) duration; 1370 mMetricsLogger.write(Helper.newLogMaker(MetricsEvent.AUTOFILL_SERVICE_DISABLED_APP, 1371 packageName, getServicePackageName(), sessionId, compatMode) 1372 .addTaggedData(MetricsEvent.FIELD_AUTOFILL_DURATION, intDuration)); 1373 } 1374 } 1375 1376 /** 1377 * Called by {@link Session} when service asked to disable autofill an app. 1378 */ disableAutofillForActivity(@onNull ComponentName componentName, long duration, int sessionId, boolean compatMode)1379 void disableAutofillForActivity(@NonNull ComponentName componentName, long duration, 1380 int sessionId, boolean compatMode) { 1381 synchronized (mLock) { 1382 if (mDisabledActivities == null) { 1383 mDisabledActivities = new ArrayMap<>(1); 1384 } 1385 long expiration = SystemClock.elapsedRealtime() + duration; 1386 // Protect it against overflow 1387 if (expiration < 0) { 1388 expiration = Long.MAX_VALUE; 1389 } 1390 mDisabledActivities.put(componentName, expiration); 1391 final int intDuration = duration > Integer.MAX_VALUE 1392 ? Integer.MAX_VALUE 1393 : (int) duration; 1394 // NOTE: not using Helper.newLogMaker() because we're setting the componentName instead 1395 // of package name 1396 final LogMaker log = new LogMaker(MetricsEvent.AUTOFILL_SERVICE_DISABLED_ACTIVITY) 1397 .setComponentName(componentName) 1398 .addTaggedData(MetricsEvent.FIELD_AUTOFILL_SERVICE, getServicePackageName()) 1399 .addTaggedData(MetricsEvent.FIELD_AUTOFILL_DURATION, intDuration) 1400 .addTaggedData(MetricsEvent.FIELD_AUTOFILL_SESSION_ID, sessionId); 1401 if (compatMode) { 1402 log.addTaggedData(MetricsEvent.FIELD_AUTOFILL_COMPAT_MODE, 1); 1403 } 1404 mMetricsLogger.write(log); 1405 } 1406 } 1407 1408 /** 1409 * Checks if autofill is disabled by service to the given activity. 1410 */ 1411 @GuardedBy("mLock") isAutofillDisabledLocked(@onNull ComponentName componentName)1412 private boolean isAutofillDisabledLocked(@NonNull ComponentName componentName) { 1413 // Check activities first. 1414 long elapsedTime = 0; 1415 if (mDisabledActivities != null) { 1416 elapsedTime = SystemClock.elapsedRealtime(); 1417 final Long expiration = mDisabledActivities.get(componentName); 1418 if (expiration != null) { 1419 if (expiration >= elapsedTime) return true; 1420 // Restriction expired - clean it up. 1421 if (sVerbose) { 1422 Slog.v(TAG, "Removing " + componentName.toShortString() 1423 + " from disabled list"); 1424 } 1425 mDisabledActivities.remove(componentName); 1426 } 1427 } 1428 1429 // Then check apps. 1430 final String packageName = componentName.getPackageName(); 1431 if (mDisabledApps == null) return false; 1432 1433 final Long expiration = mDisabledApps.get(packageName); 1434 if (expiration == null) return false; 1435 1436 if (elapsedTime == 0) { 1437 elapsedTime = SystemClock.elapsedRealtime(); 1438 } 1439 1440 if (expiration >= elapsedTime) return true; 1441 1442 // Restriction expired - clean it up. 1443 if (sVerbose) Slog.v(TAG, "Removing " + packageName + " from disabled list"); 1444 mDisabledApps.remove(packageName); 1445 return false; 1446 } 1447 1448 // Called by AutofillManager, checks UID. isFieldClassificationEnabled(int callingUid)1449 boolean isFieldClassificationEnabled(int callingUid) { 1450 synchronized (mLock) { 1451 if (!isCalledByServiceLocked("isFieldClassificationEnabled", callingUid)) { 1452 return false; 1453 } 1454 return isFieldClassificationEnabledLocked(); 1455 } 1456 } 1457 1458 // Called by internally, no need to check UID. isFieldClassificationEnabledLocked()1459 boolean isFieldClassificationEnabledLocked() { 1460 return Settings.Secure.getIntForUser( 1461 getContext().getContentResolver(), 1462 Settings.Secure.AUTOFILL_FEATURE_FIELD_CLASSIFICATION, 1, 1463 mUserId) == 1; 1464 } 1465 getFieldClassificationStrategy()1466 FieldClassificationStrategy getFieldClassificationStrategy() { 1467 return mFieldClassificationStrategy; 1468 } 1469 getAvailableFieldClassificationAlgorithms(int callingUid)1470 String[] getAvailableFieldClassificationAlgorithms(int callingUid) { 1471 synchronized (mLock) { 1472 if (!isCalledByServiceLocked("getFCAlgorithms()", callingUid)) { 1473 return null; 1474 } 1475 } 1476 return mFieldClassificationStrategy.getAvailableAlgorithms(); 1477 } 1478 getDefaultFieldClassificationAlgorithm(int callingUid)1479 String getDefaultFieldClassificationAlgorithm(int callingUid) { 1480 synchronized (mLock) { 1481 if (!isCalledByServiceLocked("getDefaultFCAlgorithm()", callingUid)) { 1482 return null; 1483 } 1484 } 1485 return mFieldClassificationStrategy.getDefaultAlgorithm(); 1486 } 1487 1488 @Override toString()1489 public String toString() { 1490 return "AutofillManagerServiceImpl: [userId=" + mUserId 1491 + ", component=" + (mInfo != null 1492 ? mInfo.getServiceInfo().getComponentName() : null) + "]"; 1493 } 1494 1495 /** Task used to prune abandoned session */ 1496 private class PruneTask extends AsyncTask<Void, Void, Void> { 1497 @Override doInBackground(Void... ignored)1498 protected Void doInBackground(Void... ignored) { 1499 int numSessionsToRemove; 1500 1501 SparseArray<IBinder> sessionsToRemove; 1502 1503 synchronized (mLock) { 1504 numSessionsToRemove = mSessions.size(); 1505 sessionsToRemove = new SparseArray<>(numSessionsToRemove); 1506 1507 for (int i = 0; i < numSessionsToRemove; i++) { 1508 Session session = mSessions.valueAt(i); 1509 1510 sessionsToRemove.put(session.id, session.getActivityTokenLocked()); 1511 } 1512 } 1513 1514 final IActivityTaskManager atm = ActivityTaskManager.getService(); 1515 1516 // Only remove sessions which's activities are not known to the activity manager anymore 1517 for (int i = 0; i < numSessionsToRemove; i++) { 1518 try { 1519 // The activity manager cannot resolve activities that have been removed 1520 if (atm.getActivityClassForToken(sessionsToRemove.valueAt(i)) != null) { 1521 sessionsToRemove.removeAt(i); 1522 i--; 1523 numSessionsToRemove--; 1524 } 1525 } catch (RemoteException e) { 1526 Slog.w(TAG, "Cannot figure out if activity is finished", e); 1527 } 1528 } 1529 1530 synchronized (mLock) { 1531 for (int i = 0; i < numSessionsToRemove; i++) { 1532 Session sessionToRemove = mSessions.get(sessionsToRemove.keyAt(i)); 1533 1534 if (sessionToRemove != null && sessionsToRemove.valueAt(i) 1535 == sessionToRemove.getActivityTokenLocked()) { 1536 if (sessionToRemove.isSavingLocked()) { 1537 if (sVerbose) { 1538 Slog.v(TAG, "Session " + sessionToRemove.id + " is saving"); 1539 } 1540 } else { 1541 if (sDebug) { 1542 Slog.i(TAG, "Prune session " + sessionToRemove.id + " (" 1543 + sessionToRemove.getActivityTokenLocked() + ")"); 1544 } 1545 sessionToRemove.removeSelfLocked(); 1546 } 1547 } 1548 } 1549 } 1550 1551 return null; 1552 } 1553 } 1554 } 1555