AutofillManagerService.java revision 5f97880714e0ee2c503bca0d7681e896c53386b0
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.Manifest.permission.MANAGE_AUTO_FILL; 20import static android.content.Context.AUTOFILL_MANAGER_SERVICE; 21 22import static com.android.server.autofill.Helper.bundleToString; 23import static com.android.server.autofill.Helper.sDebug; 24import static com.android.server.autofill.Helper.sPartitionMaxCount; 25import static com.android.server.autofill.Helper.sVerbose; 26 27import android.annotation.NonNull; 28import android.annotation.Nullable; 29import android.app.ActivityManager; 30import android.app.ActivityThread; 31import android.content.BroadcastReceiver; 32import android.content.ComponentName; 33import android.content.ContentResolver; 34import android.content.Context; 35import android.content.Intent; 36import android.content.IntentFilter; 37import android.content.pm.PackageManager; 38import android.content.pm.UserInfo; 39import android.database.ContentObserver; 40import android.graphics.Rect; 41import android.net.Uri; 42import android.os.Binder; 43import android.os.Build; 44import android.os.Bundle; 45import android.os.Handler; 46import android.os.IBinder; 47import android.os.RemoteException; 48import android.os.ResultReceiver; 49import android.os.ShellCallback; 50import android.os.UserHandle; 51import android.os.UserManager; 52import android.os.UserManagerInternal; 53import android.provider.Settings; 54import android.service.autofill.FillEventHistory; 55import android.util.LocalLog; 56import android.util.Slog; 57import android.util.SparseArray; 58import android.util.SparseBooleanArray; 59import android.view.autofill.AutofillId; 60import android.view.autofill.AutofillManager; 61import android.view.autofill.AutofillManagerInternal; 62import android.view.autofill.AutofillValue; 63import android.view.autofill.IAutoFillManager; 64import android.view.autofill.IAutoFillManagerClient; 65 66import com.android.internal.annotations.GuardedBy; 67import com.android.internal.content.PackageMonitor; 68import com.android.internal.os.BackgroundThread; 69import com.android.internal.os.IResultReceiver; 70import com.android.internal.util.DumpUtils; 71import com.android.internal.util.Preconditions; 72import com.android.server.FgThread; 73import com.android.server.LocalServices; 74import com.android.server.SystemService; 75import com.android.server.autofill.ui.AutoFillUI; 76 77import java.io.FileDescriptor; 78import java.io.PrintWriter; 79import java.util.ArrayList; 80import java.util.List; 81import java.util.Objects; 82 83/** 84 * Entry point service for autofill management. 85 * 86 * <p>This service provides the {@link IAutoFillManager} implementation and keeps a list of 87 * {@link AutofillManagerServiceImpl} per user; the real work is done by 88 * {@link AutofillManagerServiceImpl} itself. 89 */ 90public final class AutofillManagerService extends SystemService { 91 92 private static final String TAG = "AutofillManagerService"; 93 94 static final String RECEIVER_BUNDLE_EXTRA_SESSIONS = "sessions"; 95 96 private final Context mContext; 97 private final AutoFillUI mUi; 98 99 private final Object mLock = new Object(); 100 101 /** 102 * Cache of {@link AutofillManagerServiceImpl} per user id. 103 * <p> 104 * It has to be mapped by user id because the same current user could have simultaneous sessions 105 * associated to different user profiles (for example, in a multi-window environment or when 106 * device has work profiles). 107 */ 108 @GuardedBy("mLock") 109 private SparseArray<AutofillManagerServiceImpl> mServicesCache = new SparseArray<>(); 110 111 /** 112 * Users disabled due to {@link UserManager} restrictions. 113 */ 114 @GuardedBy("mLock") 115 private final SparseBooleanArray mDisabledUsers = new SparseBooleanArray(); 116 117 private final LocalLog mRequestsHistory = new LocalLog(20); 118 119 private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { 120 @Override 121 public void onReceive(Context context, Intent intent) { 122 if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(intent.getAction())) { 123 mUi.hideAll(null); 124 } 125 } 126 }; 127 128 public AutofillManagerService(Context context) { 129 super(context); 130 mContext = context; 131 mUi = new AutoFillUI(ActivityThread.currentActivityThread().getSystemUiContext()); 132 133 final boolean debug = Build.IS_DEBUGGABLE; 134 Slog.i(TAG, "Setting debug to " + debug); 135 setDebugLocked(debug); 136 137 final IntentFilter filter = new IntentFilter(); 138 filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS); 139 mContext.registerReceiver(mBroadcastReceiver, filter, null, FgThread.getHandler()); 140 141 // Hookup with UserManager to disable service when necessary. 142 final UserManager um = context.getSystemService(UserManager.class); 143 final UserManagerInternal umi = LocalServices.getService(UserManagerInternal.class); 144 final List<UserInfo> users = um.getUsers(); 145 for (int i = 0; i < users.size(); i++) { 146 final int userId = users.get(i).id; 147 final boolean disabled = umi.getUserRestriction(userId, UserManager.DISALLOW_AUTOFILL); 148 if (disabled) { 149 if (disabled) { 150 Slog.i(TAG, "Disabling Autofill for user " + userId); 151 } 152 mDisabledUsers.put(userId, disabled); 153 } 154 } 155 umi.addUserRestrictionsListener((userId, newRestrictions, prevRestrictions) -> { 156 final boolean disabledNow = 157 newRestrictions.getBoolean(UserManager.DISALLOW_AUTOFILL, false); 158 synchronized (mLock) { 159 final boolean disabledBefore = mDisabledUsers.get(userId); 160 if (disabledBefore == disabledNow) { 161 // Nothing changed, do nothing. 162 if (sDebug) { 163 Slog.d(TAG, "Autofill restriction did not change for user " + userId + ": " 164 + bundleToString(newRestrictions)); 165 return; 166 } 167 } 168 Slog.i(TAG, "Updating Autofill for user " + userId + ": disabled=" + disabledNow); 169 mDisabledUsers.put(userId, disabledNow); 170 updateCachedServiceLocked(userId, disabledNow); 171 } 172 }); 173 startTrackingPackageChanges(); 174 } 175 176 private void startTrackingPackageChanges() { 177 PackageMonitor monitor = new PackageMonitor() { 178 @Override 179 public void onSomePackagesChanged() { 180 synchronized (mLock) { 181 updateCachedServiceLocked(getChangingUserId()); 182 } 183 } 184 185 @Override 186 public void onPackageUpdateFinished(String packageName, int uid) { 187 synchronized (mLock) { 188 final String activePackageName = getActiveAutofillServicePackageName(); 189 if (packageName.equals(activePackageName)) { 190 removeCachedServiceLocked(getChangingUserId()); 191 } 192 } 193 } 194 195 @Override 196 public void onPackageRemoved(String packageName, int uid) { 197 synchronized (mLock) { 198 final int userId = getChangingUserId(); 199 final AutofillManagerServiceImpl userState = peekServiceForUserLocked(userId); 200 if (userState != null) { 201 final ComponentName componentName = userState.getServiceComponentName(); 202 if (componentName != null) { 203 if (packageName.equals(componentName.getPackageName())) { 204 handleActiveAutofillServiceRemoved(userId); 205 } 206 } 207 } 208 } 209 } 210 211 @Override 212 public boolean onHandleForceStop(Intent intent, String[] packages, 213 int uid, boolean doit) { 214 synchronized (mLock) { 215 final String activePackageName = getActiveAutofillServicePackageName(); 216 for (String pkg : packages) { 217 if (pkg.equals(activePackageName)) { 218 if (!doit) { 219 return true; 220 } 221 removeCachedServiceLocked(getChangingUserId()); 222 } 223 } 224 } 225 return false; 226 } 227 228 private void handleActiveAutofillServiceRemoved(int userId) { 229 removeCachedServiceLocked(userId); 230 Settings.Secure.putStringForUser(mContext.getContentResolver(), 231 Settings.Secure.AUTOFILL_SERVICE, null, userId); 232 } 233 234 private String getActiveAutofillServicePackageName() { 235 final int userId = getChangingUserId(); 236 final AutofillManagerServiceImpl userState = peekServiceForUserLocked(userId); 237 if (userState == null) { 238 return null; 239 } 240 final ComponentName serviceComponent = userState.getServiceComponentName(); 241 if (serviceComponent == null) { 242 return null; 243 } 244 return serviceComponent.getPackageName(); 245 } 246 }; 247 248 // package changes 249 monitor.register(mContext, null, UserHandle.ALL, true); 250 } 251 252 @Override 253 public void onStart() { 254 publishBinderService(AUTOFILL_MANAGER_SERVICE, new AutoFillManagerServiceStub()); 255 publishLocalService(AutofillManagerInternal.class, new LocalService()); 256 } 257 258 @Override 259 public void onBootPhase(int phase) { 260 if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) { 261 new SettingsObserver(BackgroundThread.getHandler()); 262 } 263 } 264 265 @Override 266 public void onUnlockUser(int userId) { 267 synchronized (mLock) { 268 updateCachedServiceLocked(userId); 269 } 270 } 271 272 @Override 273 public void onCleanupUser(int userId) { 274 synchronized (mLock) { 275 removeCachedServiceLocked(userId); 276 } 277 } 278 279 /** 280 * Gets the service instance for an user. 281 * 282 * @return service instance. 283 */ 284 @NonNull 285 AutofillManagerServiceImpl getServiceForUserLocked(int userId) { 286 final int resolvedUserId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), 287 Binder.getCallingUid(), userId, false, false, null, null); 288 AutofillManagerServiceImpl service = mServicesCache.get(resolvedUserId); 289 if (service == null) { 290 service = new AutofillManagerServiceImpl(mContext, mLock, mRequestsHistory, 291 resolvedUserId, mUi, mDisabledUsers.get(resolvedUserId)); 292 mServicesCache.put(userId, service); 293 } 294 return service; 295 } 296 297 /** 298 * Peeks the service instance for a user. 299 * 300 * @return service instance or {@code null} if not already present 301 */ 302 @Nullable 303 AutofillManagerServiceImpl peekServiceForUserLocked(int userId) { 304 final int resolvedUserId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), 305 Binder.getCallingUid(), userId, false, false, null, null); 306 return mServicesCache.get(resolvedUserId); 307 } 308 309 // Called by Shell command. 310 void destroySessions(int userId, IResultReceiver receiver) { 311 Slog.i(TAG, "destroySessions() for userId " + userId); 312 mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG); 313 314 synchronized (mLock) { 315 if (userId != UserHandle.USER_ALL) { 316 AutofillManagerServiceImpl service = peekServiceForUserLocked(userId); 317 if (service != null) { 318 service.destroySessionsLocked(); 319 } 320 } else { 321 final int size = mServicesCache.size(); 322 for (int i = 0; i < size; i++) { 323 mServicesCache.valueAt(i).destroySessionsLocked(); 324 } 325 } 326 } 327 328 try { 329 receiver.send(0, new Bundle()); 330 } catch (RemoteException e) { 331 // Just ignore it... 332 } 333 } 334 335 // Called by Shell command. 336 void listSessions(int userId, IResultReceiver receiver) { 337 Slog.i(TAG, "listSessions() for userId " + userId); 338 mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG); 339 340 final Bundle resultData = new Bundle(); 341 final ArrayList<String> sessions = new ArrayList<>(); 342 343 synchronized (mLock) { 344 if (userId != UserHandle.USER_ALL) { 345 AutofillManagerServiceImpl service = peekServiceForUserLocked(userId); 346 if (service != null) { 347 service.listSessionsLocked(sessions); 348 } 349 } else { 350 final int size = mServicesCache.size(); 351 for (int i = 0; i < size; i++) { 352 mServicesCache.valueAt(i).listSessionsLocked(sessions); 353 } 354 } 355 } 356 357 resultData.putStringArrayList(RECEIVER_BUNDLE_EXTRA_SESSIONS, sessions); 358 try { 359 receiver.send(0, resultData); 360 } catch (RemoteException e) { 361 // Just ignore it... 362 } 363 } 364 365 // Called by Shell command. 366 void reset() { 367 Slog.i(TAG, "reset()"); 368 mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG); 369 370 synchronized (mLock) { 371 final int size = mServicesCache.size(); 372 for (int i = 0; i < size; i++) { 373 mServicesCache.valueAt(i).destroyLocked(); 374 } 375 mServicesCache.clear(); 376 } 377 } 378 379 // Called by Shell command. 380 void setLogLevel(int level) { 381 Slog.i(TAG, "setLogLevel(): " + level); 382 mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG); 383 384 boolean debug = false; 385 boolean verbose = false; 386 if (level == AutofillManager.FLAG_ADD_CLIENT_VERBOSE) { 387 debug = verbose = true; 388 } else if (level == AutofillManager.FLAG_ADD_CLIENT_DEBUG) { 389 debug = true; 390 } 391 synchronized (mLock) { 392 setDebugLocked(debug); 393 setVerboseLocked(verbose); 394 } 395 } 396 397 // Called by Shell command. 398 int getLogLevel() { 399 mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG); 400 401 synchronized (mLock) { 402 if (sVerbose) return AutofillManager.FLAG_ADD_CLIENT_VERBOSE; 403 if (sDebug) return AutofillManager.FLAG_ADD_CLIENT_DEBUG; 404 return 0; 405 } 406 } 407 408 // Called by Shell command. 409 public int getMaxPartitions() { 410 mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG); 411 412 synchronized (mLock) { 413 return sPartitionMaxCount; 414 } 415 } 416 417 // Called by Shell command. 418 public void setMaxPartitions(int max) { 419 mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG); 420 Slog.i(TAG, "setMaxPartitions(): " + max); 421 synchronized (mLock) { 422 sPartitionMaxCount = max; 423 } 424 } 425 426 private void setDebugLocked(boolean debug) { 427 com.android.server.autofill.Helper.sDebug = debug; 428 android.view.autofill.Helper.sDebug = debug; 429 } 430 431 432 private void setVerboseLocked(boolean verbose) { 433 com.android.server.autofill.Helper.sVerbose = verbose; 434 android.view.autofill.Helper.sVerbose = verbose; 435 } 436 437 /** 438 * Removes a cached service for a given user. 439 */ 440 private void removeCachedServiceLocked(int userId) { 441 final AutofillManagerServiceImpl service = peekServiceForUserLocked(userId); 442 if (service != null) { 443 mServicesCache.delete(userId); 444 service.destroyLocked(); 445 } 446 } 447 448 /** 449 * Updates a cached service for a given user. 450 */ 451 private void updateCachedServiceLocked(int userId) { 452 updateCachedServiceLocked(userId, mDisabledUsers.get(userId)); 453 } 454 455 /** 456 * Updates a cached service for a given user. 457 */ 458 private void updateCachedServiceLocked(int userId, boolean disabled) { 459 AutofillManagerServiceImpl service = getServiceForUserLocked(userId); 460 if (service != null) { 461 service.updateLocked(disabled); 462 if (!service.isEnabled()) { 463 removeCachedServiceLocked(userId); 464 } 465 } 466 } 467 468 private final class LocalService extends AutofillManagerInternal { 469 470 @Override 471 public void onBackKeyPressed() { 472 if (sDebug) Slog.d(TAG, "onBackKeyPressed()"); 473 mUi.hideAll(null); 474 } 475 } 476 477 final class AutoFillManagerServiceStub extends IAutoFillManager.Stub { 478 @Override 479 public int addClient(IAutoFillManagerClient client, int userId) { 480 synchronized (mLock) { 481 int flags = 0; 482 if (getServiceForUserLocked(userId).addClientLocked(client)) { 483 flags |= AutofillManager.FLAG_ADD_CLIENT_ENABLED; 484 } 485 if (sDebug) { 486 flags |= AutofillManager.FLAG_ADD_CLIENT_DEBUG; 487 } 488 if (sVerbose) { 489 flags |= AutofillManager.FLAG_ADD_CLIENT_VERBOSE; 490 } 491 return flags; 492 } 493 } 494 495 @Override 496 public void setAuthenticationResult(Bundle data, int sessionId, int authenticationId, 497 int userId) { 498 synchronized (mLock) { 499 final AutofillManagerServiceImpl service = getServiceForUserLocked(userId); 500 service.setAuthenticationResultLocked(data, sessionId, authenticationId, 501 getCallingUid()); 502 } 503 } 504 505 @Override 506 public void setHasCallback(int sessionId, int userId, boolean hasIt) { 507 synchronized (mLock) { 508 final AutofillManagerServiceImpl service = getServiceForUserLocked(userId); 509 service.setHasCallback(sessionId, getCallingUid(), hasIt); 510 } 511 } 512 513 @Override 514 public int startSession(IBinder activityToken, IBinder appCallback, AutofillId autofillId, 515 Rect bounds, AutofillValue value, int userId, boolean hasCallback, int flags, 516 String packageName) { 517 518 activityToken = Preconditions.checkNotNull(activityToken, "activityToken"); 519 appCallback = Preconditions.checkNotNull(appCallback, "appCallback"); 520 autofillId = Preconditions.checkNotNull(autofillId, "autoFillId"); 521 packageName = Preconditions.checkNotNull(packageName, "packageName"); 522 523 Preconditions.checkArgument(userId == UserHandle.getUserId(getCallingUid()), "userId"); 524 525 try { 526 mContext.getPackageManager().getPackageInfoAsUser(packageName, 0, userId); 527 } catch (PackageManager.NameNotFoundException e) { 528 throw new IllegalArgumentException(packageName + " is not a valid package", e); 529 } 530 531 synchronized (mLock) { 532 final AutofillManagerServiceImpl service = getServiceForUserLocked(userId); 533 return service.startSessionLocked(activityToken, getCallingUid(), appCallback, 534 autofillId, bounds, value, hasCallback, flags, packageName); 535 } 536 } 537 538 @Override 539 public FillEventHistory getFillEventHistory() throws RemoteException { 540 UserHandle user = getCallingUserHandle(); 541 int uid = getCallingUid(); 542 543 synchronized (mLock) { 544 AutofillManagerServiceImpl service = peekServiceForUserLocked(user.getIdentifier()); 545 if (service != null) { 546 return service.getFillEventHistory(uid); 547 } 548 } 549 550 return null; 551 } 552 553 @Override 554 public boolean restoreSession(int sessionId, IBinder activityToken, IBinder appCallback) 555 throws RemoteException { 556 activityToken = Preconditions.checkNotNull(activityToken, "activityToken"); 557 appCallback = Preconditions.checkNotNull(appCallback, "appCallback"); 558 559 synchronized (mLock) { 560 final AutofillManagerServiceImpl service = mServicesCache.get( 561 UserHandle.getCallingUserId()); 562 if (service != null) { 563 return service.restoreSession(sessionId, getCallingUid(), activityToken, 564 appCallback); 565 } 566 } 567 568 return false; 569 } 570 571 @Override 572 public void updateSession(int sessionId, AutofillId autoFillId, Rect bounds, 573 AutofillValue value, int action, int flags, int userId) { 574 synchronized (mLock) { 575 final AutofillManagerServiceImpl service = peekServiceForUserLocked(userId); 576 if (service != null) { 577 service.updateSessionLocked(sessionId, getCallingUid(), autoFillId, bounds, 578 value, action, flags); 579 } 580 } 581 } 582 583 @Override 584 public int updateOrRestartSession(IBinder activityToken, IBinder appCallback, 585 AutofillId autoFillId, Rect bounds, AutofillValue value, int userId, 586 boolean hasCallback, int flags, String packageName, int sessionId, int action) { 587 boolean restart = false; 588 synchronized (mLock) { 589 final AutofillManagerServiceImpl service = peekServiceForUserLocked(userId); 590 if (service != null) { 591 restart = service.updateSessionLocked(sessionId, getCallingUid(), autoFillId, 592 bounds, value, action, flags); 593 } 594 } 595 if (restart) { 596 return startSession(activityToken, appCallback, autoFillId, bounds, value, userId, 597 hasCallback, flags, packageName); 598 } 599 600 // Nothing changed... 601 return sessionId; 602 } 603 604 @Override 605 public void finishSession(int sessionId, int userId) { 606 synchronized (mLock) { 607 final AutofillManagerServiceImpl service = peekServiceForUserLocked(userId); 608 if (service != null) { 609 service.finishSessionLocked(sessionId, getCallingUid()); 610 } 611 } 612 } 613 614 @Override 615 public void cancelSession(int sessionId, int userId) { 616 synchronized (mLock) { 617 final AutofillManagerServiceImpl service = peekServiceForUserLocked(userId); 618 if (service != null) { 619 service.cancelSessionLocked(sessionId, getCallingUid()); 620 } 621 } 622 } 623 624 @Override 625 public void disableOwnedAutofillServices(int userId) { 626 synchronized (mLock) { 627 final AutofillManagerServiceImpl service = peekServiceForUserLocked(userId); 628 if (service != null) { 629 service.disableOwnedAutofillServicesLocked(Binder.getCallingUid()); 630 } 631 } 632 } 633 634 @Override 635 public boolean isServiceSupported(int userId) { 636 synchronized (mLock) { 637 return !mDisabledUsers.get(userId); 638 } 639 } 640 641 @Override 642 public boolean isServiceEnabled(int userId, String packageName) { 643 synchronized (mLock) { 644 final AutofillManagerServiceImpl service = peekServiceForUserLocked(userId); 645 if (service == null) return false; 646 return Objects.equals(packageName, service.getPackageName()); 647 } 648 } 649 650 @Override 651 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 652 if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return; 653 654 boolean showHistory = true; 655 boolean uiOnly = false; 656 if (args != null) { 657 for (String arg : args) { 658 switch(arg) { 659 case "--no-history": 660 showHistory = false; 661 break; 662 case "--ui-only": 663 uiOnly = true; 664 break; 665 case "--help": 666 pw.println("Usage: dumpsys autofill [--ui-only|--no-history]"); 667 return; 668 default: 669 Slog.w(TAG, "Ignoring invalid dump arg: " + arg); 670 } 671 } 672 } 673 674 if (uiOnly) { 675 mUi.dump(pw); 676 return; 677 } 678 679 boolean oldDebug = sDebug; 680 try { 681 synchronized (mLock) { 682 oldDebug = sDebug; 683 setDebugLocked(true); 684 pw.print("Debug mode: "); pw.println(oldDebug); 685 pw.print("Verbose mode: "); pw.println(sVerbose); 686 pw.print("Disabled users: "); pw.println(mDisabledUsers); 687 pw.print("Max partitions per session: "); pw.println(sPartitionMaxCount); 688 final int size = mServicesCache.size(); 689 pw.print("Cached services: "); 690 if (size == 0) { 691 pw.println("none"); 692 } else { 693 pw.println(size); 694 for (int i = 0; i < size; i++) { 695 pw.print("\nService at index "); pw.println(i); 696 final AutofillManagerServiceImpl impl = mServicesCache.valueAt(i); 697 impl.dumpLocked(" ", pw); 698 } 699 } 700 mUi.dump(pw); 701 } 702 if (showHistory) { 703 pw.println("Requests history:"); 704 mRequestsHistory.reverseDump(fd, pw, args); 705 } 706 } finally { 707 setDebugLocked(oldDebug); 708 } 709 } 710 711 @Override 712 public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err, 713 String[] args, ShellCallback callback, ResultReceiver resultReceiver) { 714 (new AutofillManagerServiceShellCommand(AutofillManagerService.this)).exec( 715 this, in, out, err, args, callback, resultReceiver); 716 } 717 } 718 719 private final class SettingsObserver extends ContentObserver { 720 SettingsObserver(Handler handler) { 721 super(handler); 722 ContentResolver resolver = mContext.getContentResolver(); 723 resolver.registerContentObserver(Settings.Secure.getUriFor( 724 Settings.Secure.AUTOFILL_SERVICE), false, this, UserHandle.USER_ALL); 725 resolver.registerContentObserver(Settings.Secure.getUriFor( 726 Settings.Secure.USER_SETUP_COMPLETE), false, this, UserHandle.USER_ALL); 727 } 728 729 @Override 730 public void onChange(boolean selfChange, Uri uri, int userId) { 731 if (sVerbose) Slog.v(TAG, "onChange(): uri=" + uri + ", userId=" + userId); 732 synchronized (mLock) { 733 updateCachedServiceLocked(userId); 734 } 735 } 736 } 737} 738