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 onSwitchUser(int userHandle) { 274 if (sDebug) Slog.d(TAG, "Hiding UI when user switched"); 275 mUi.hideAll(null); 276 } 277 278 @Override 279 public void onCleanupUser(int userId) { 280 synchronized (mLock) { 281 removeCachedServiceLocked(userId); 282 } 283 } 284 285 /** 286 * Gets the service instance for an user. 287 * 288 * @return service instance. 289 */ 290 @NonNull 291 AutofillManagerServiceImpl getServiceForUserLocked(int userId) { 292 final int resolvedUserId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), 293 Binder.getCallingUid(), userId, false, false, null, null); 294 AutofillManagerServiceImpl service = mServicesCache.get(resolvedUserId); 295 if (service == null) { 296 service = new AutofillManagerServiceImpl(mContext, mLock, mRequestsHistory, 297 resolvedUserId, mUi, mDisabledUsers.get(resolvedUserId)); 298 mServicesCache.put(userId, service); 299 } 300 return service; 301 } 302 303 /** 304 * Peeks the service instance for a user. 305 * 306 * @return service instance or {@code null} if not already present 307 */ 308 @Nullable 309 AutofillManagerServiceImpl peekServiceForUserLocked(int userId) { 310 final int resolvedUserId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), 311 Binder.getCallingUid(), userId, false, false, null, null); 312 return mServicesCache.get(resolvedUserId); 313 } 314 315 // Called by Shell command. 316 void destroySessions(int userId, IResultReceiver receiver) { 317 Slog.i(TAG, "destroySessions() for userId " + userId); 318 mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG); 319 320 synchronized (mLock) { 321 if (userId != UserHandle.USER_ALL) { 322 AutofillManagerServiceImpl service = peekServiceForUserLocked(userId); 323 if (service != null) { 324 service.destroySessionsLocked(); 325 } 326 } else { 327 final int size = mServicesCache.size(); 328 for (int i = 0; i < size; i++) { 329 mServicesCache.valueAt(i).destroySessionsLocked(); 330 } 331 } 332 } 333 334 try { 335 receiver.send(0, new Bundle()); 336 } catch (RemoteException e) { 337 // Just ignore it... 338 } 339 } 340 341 // Called by Shell command. 342 void listSessions(int userId, IResultReceiver receiver) { 343 Slog.i(TAG, "listSessions() for userId " + userId); 344 mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG); 345 346 final Bundle resultData = new Bundle(); 347 final ArrayList<String> sessions = new ArrayList<>(); 348 349 synchronized (mLock) { 350 if (userId != UserHandle.USER_ALL) { 351 AutofillManagerServiceImpl service = peekServiceForUserLocked(userId); 352 if (service != null) { 353 service.listSessionsLocked(sessions); 354 } 355 } else { 356 final int size = mServicesCache.size(); 357 for (int i = 0; i < size; i++) { 358 mServicesCache.valueAt(i).listSessionsLocked(sessions); 359 } 360 } 361 } 362 363 resultData.putStringArrayList(RECEIVER_BUNDLE_EXTRA_SESSIONS, sessions); 364 try { 365 receiver.send(0, resultData); 366 } catch (RemoteException e) { 367 // Just ignore it... 368 } 369 } 370 371 // Called by Shell command. 372 void reset() { 373 Slog.i(TAG, "reset()"); 374 mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG); 375 376 synchronized (mLock) { 377 final int size = mServicesCache.size(); 378 for (int i = 0; i < size; i++) { 379 mServicesCache.valueAt(i).destroyLocked(); 380 } 381 mServicesCache.clear(); 382 } 383 } 384 385 // Called by Shell command. 386 void setLogLevel(int level) { 387 Slog.i(TAG, "setLogLevel(): " + level); 388 mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG); 389 390 boolean debug = false; 391 boolean verbose = false; 392 if (level == AutofillManager.FLAG_ADD_CLIENT_VERBOSE) { 393 debug = verbose = true; 394 } else if (level == AutofillManager.FLAG_ADD_CLIENT_DEBUG) { 395 debug = true; 396 } 397 synchronized (mLock) { 398 setDebugLocked(debug); 399 setVerboseLocked(verbose); 400 } 401 } 402 403 // Called by Shell command. 404 int getLogLevel() { 405 mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG); 406 407 synchronized (mLock) { 408 if (sVerbose) return AutofillManager.FLAG_ADD_CLIENT_VERBOSE; 409 if (sDebug) return AutofillManager.FLAG_ADD_CLIENT_DEBUG; 410 return 0; 411 } 412 } 413 414 // Called by Shell command. 415 public int getMaxPartitions() { 416 mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG); 417 418 synchronized (mLock) { 419 return sPartitionMaxCount; 420 } 421 } 422 423 // Called by Shell command. 424 public void setMaxPartitions(int max) { 425 mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG); 426 Slog.i(TAG, "setMaxPartitions(): " + max); 427 synchronized (mLock) { 428 sPartitionMaxCount = max; 429 } 430 } 431 432 private void setDebugLocked(boolean debug) { 433 com.android.server.autofill.Helper.sDebug = debug; 434 android.view.autofill.Helper.sDebug = debug; 435 } 436 437 438 private void setVerboseLocked(boolean verbose) { 439 com.android.server.autofill.Helper.sVerbose = verbose; 440 android.view.autofill.Helper.sVerbose = verbose; 441 } 442 443 /** 444 * Removes a cached service for a given user. 445 */ 446 private void removeCachedServiceLocked(int userId) { 447 final AutofillManagerServiceImpl service = peekServiceForUserLocked(userId); 448 if (service != null) { 449 mServicesCache.delete(userId); 450 service.destroyLocked(); 451 } 452 } 453 454 /** 455 * Updates a cached service for a given user. 456 */ 457 private void updateCachedServiceLocked(int userId) { 458 updateCachedServiceLocked(userId, mDisabledUsers.get(userId)); 459 } 460 461 /** 462 * Updates a cached service for a given user. 463 */ 464 private void updateCachedServiceLocked(int userId, boolean disabled) { 465 AutofillManagerServiceImpl service = getServiceForUserLocked(userId); 466 if (service != null) { 467 service.updateLocked(disabled); 468 if (!service.isEnabled()) { 469 removeCachedServiceLocked(userId); 470 } 471 } 472 } 473 474 private final class LocalService extends AutofillManagerInternal { 475 476 @Override 477 public void onBackKeyPressed() { 478 if (sDebug) Slog.d(TAG, "onBackKeyPressed()"); 479 mUi.hideAll(null); 480 } 481 } 482 483 final class AutoFillManagerServiceStub extends IAutoFillManager.Stub { 484 @Override 485 public int addClient(IAutoFillManagerClient client, int userId) { 486 synchronized (mLock) { 487 int flags = 0; 488 if (getServiceForUserLocked(userId).addClientLocked(client)) { 489 flags |= AutofillManager.FLAG_ADD_CLIENT_ENABLED; 490 } 491 if (sDebug) { 492 flags |= AutofillManager.FLAG_ADD_CLIENT_DEBUG; 493 } 494 if (sVerbose) { 495 flags |= AutofillManager.FLAG_ADD_CLIENT_VERBOSE; 496 } 497 return flags; 498 } 499 } 500 501 @Override 502 public void setAuthenticationResult(Bundle data, int sessionId, int authenticationId, 503 int userId) { 504 synchronized (mLock) { 505 final AutofillManagerServiceImpl service = getServiceForUserLocked(userId); 506 service.setAuthenticationResultLocked(data, sessionId, authenticationId, 507 getCallingUid()); 508 } 509 } 510 511 @Override 512 public void setHasCallback(int sessionId, int userId, boolean hasIt) { 513 synchronized (mLock) { 514 final AutofillManagerServiceImpl service = getServiceForUserLocked(userId); 515 service.setHasCallback(sessionId, getCallingUid(), hasIt); 516 } 517 } 518 519 @Override 520 public int startSession(IBinder activityToken, IBinder appCallback, AutofillId autofillId, 521 Rect bounds, AutofillValue value, int userId, boolean hasCallback, int flags, 522 String packageName) { 523 524 activityToken = Preconditions.checkNotNull(activityToken, "activityToken"); 525 appCallback = Preconditions.checkNotNull(appCallback, "appCallback"); 526 autofillId = Preconditions.checkNotNull(autofillId, "autoFillId"); 527 packageName = Preconditions.checkNotNull(packageName, "packageName"); 528 529 Preconditions.checkArgument(userId == UserHandle.getUserId(getCallingUid()), "userId"); 530 531 try { 532 mContext.getPackageManager().getPackageInfoAsUser(packageName, 0, userId); 533 } catch (PackageManager.NameNotFoundException e) { 534 throw new IllegalArgumentException(packageName + " is not a valid package", e); 535 } 536 537 synchronized (mLock) { 538 final AutofillManagerServiceImpl service = getServiceForUserLocked(userId); 539 return service.startSessionLocked(activityToken, getCallingUid(), appCallback, 540 autofillId, bounds, value, hasCallback, flags, packageName); 541 } 542 } 543 544 @Override 545 public FillEventHistory getFillEventHistory() throws RemoteException { 546 UserHandle user = getCallingUserHandle(); 547 int uid = getCallingUid(); 548 549 synchronized (mLock) { 550 AutofillManagerServiceImpl service = peekServiceForUserLocked(user.getIdentifier()); 551 if (service != null) { 552 return service.getFillEventHistory(uid); 553 } 554 } 555 556 return null; 557 } 558 559 @Override 560 public boolean restoreSession(int sessionId, IBinder activityToken, IBinder appCallback) 561 throws RemoteException { 562 activityToken = Preconditions.checkNotNull(activityToken, "activityToken"); 563 appCallback = Preconditions.checkNotNull(appCallback, "appCallback"); 564 565 synchronized (mLock) { 566 final AutofillManagerServiceImpl service = mServicesCache.get( 567 UserHandle.getCallingUserId()); 568 if (service != null) { 569 return service.restoreSession(sessionId, getCallingUid(), activityToken, 570 appCallback); 571 } 572 } 573 574 return false; 575 } 576 577 @Override 578 public void updateSession(int sessionId, AutofillId autoFillId, Rect bounds, 579 AutofillValue value, int action, int flags, int userId) { 580 synchronized (mLock) { 581 final AutofillManagerServiceImpl service = peekServiceForUserLocked(userId); 582 if (service != null) { 583 service.updateSessionLocked(sessionId, getCallingUid(), autoFillId, bounds, 584 value, action, flags); 585 } 586 } 587 } 588 589 @Override 590 public int updateOrRestartSession(IBinder activityToken, IBinder appCallback, 591 AutofillId autoFillId, Rect bounds, AutofillValue value, int userId, 592 boolean hasCallback, int flags, String packageName, int sessionId, int action) { 593 boolean restart = false; 594 synchronized (mLock) { 595 final AutofillManagerServiceImpl service = peekServiceForUserLocked(userId); 596 if (service != null) { 597 restart = service.updateSessionLocked(sessionId, getCallingUid(), autoFillId, 598 bounds, value, action, flags); 599 } 600 } 601 if (restart) { 602 return startSession(activityToken, appCallback, autoFillId, bounds, value, userId, 603 hasCallback, flags, packageName); 604 } 605 606 // Nothing changed... 607 return sessionId; 608 } 609 610 @Override 611 public void finishSession(int sessionId, int userId) { 612 synchronized (mLock) { 613 final AutofillManagerServiceImpl service = peekServiceForUserLocked(userId); 614 if (service != null) { 615 service.finishSessionLocked(sessionId, getCallingUid()); 616 } 617 } 618 } 619 620 @Override 621 public void cancelSession(int sessionId, int userId) { 622 synchronized (mLock) { 623 final AutofillManagerServiceImpl service = peekServiceForUserLocked(userId); 624 if (service != null) { 625 service.cancelSessionLocked(sessionId, getCallingUid()); 626 } 627 } 628 } 629 630 @Override 631 public void disableOwnedAutofillServices(int userId) { 632 synchronized (mLock) { 633 final AutofillManagerServiceImpl service = peekServiceForUserLocked(userId); 634 if (service != null) { 635 service.disableOwnedAutofillServicesLocked(Binder.getCallingUid()); 636 } 637 } 638 } 639 640 @Override 641 public boolean isServiceSupported(int userId) { 642 synchronized (mLock) { 643 return !mDisabledUsers.get(userId); 644 } 645 } 646 647 @Override 648 public boolean isServiceEnabled(int userId, String packageName) { 649 synchronized (mLock) { 650 final AutofillManagerServiceImpl service = peekServiceForUserLocked(userId); 651 if (service == null) return false; 652 return Objects.equals(packageName, service.getPackageName()); 653 } 654 } 655 656 @Override 657 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 658 if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return; 659 660 boolean showHistory = true; 661 boolean uiOnly = false; 662 if (args != null) { 663 for (String arg : args) { 664 switch(arg) { 665 case "--no-history": 666 showHistory = false; 667 break; 668 case "--ui-only": 669 uiOnly = true; 670 break; 671 case "--help": 672 pw.println("Usage: dumpsys autofill [--ui-only|--no-history]"); 673 return; 674 default: 675 Slog.w(TAG, "Ignoring invalid dump arg: " + arg); 676 } 677 } 678 } 679 680 if (uiOnly) { 681 mUi.dump(pw); 682 return; 683 } 684 685 boolean oldDebug = sDebug; 686 try { 687 synchronized (mLock) { 688 oldDebug = sDebug; 689 setDebugLocked(true); 690 pw.print("Debug mode: "); pw.println(oldDebug); 691 pw.print("Verbose mode: "); pw.println(sVerbose); 692 pw.print("Disabled users: "); pw.println(mDisabledUsers); 693 pw.print("Max partitions per session: "); pw.println(sPartitionMaxCount); 694 final int size = mServicesCache.size(); 695 pw.print("Cached services: "); 696 if (size == 0) { 697 pw.println("none"); 698 } else { 699 pw.println(size); 700 for (int i = 0; i < size; i++) { 701 pw.print("\nService at index "); pw.println(i); 702 final AutofillManagerServiceImpl impl = mServicesCache.valueAt(i); 703 impl.dumpLocked(" ", pw); 704 } 705 } 706 mUi.dump(pw); 707 } 708 if (showHistory) { 709 pw.println("Requests history:"); 710 mRequestsHistory.reverseDump(fd, pw, args); 711 } 712 } finally { 713 setDebugLocked(oldDebug); 714 } 715 } 716 717 @Override 718 public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err, 719 String[] args, ShellCallback callback, ResultReceiver resultReceiver) { 720 (new AutofillManagerServiceShellCommand(AutofillManagerService.this)).exec( 721 this, in, out, err, args, callback, resultReceiver); 722 } 723 } 724 725 private final class SettingsObserver extends ContentObserver { 726 SettingsObserver(Handler handler) { 727 super(handler); 728 ContentResolver resolver = mContext.getContentResolver(); 729 resolver.registerContentObserver(Settings.Secure.getUriFor( 730 Settings.Secure.AUTOFILL_SERVICE), false, this, UserHandle.USER_ALL); 731 resolver.registerContentObserver(Settings.Secure.getUriFor( 732 Settings.Secure.USER_SETUP_COMPLETE), false, this, UserHandle.USER_ALL); 733 } 734 735 @Override 736 public void onChange(boolean selfChange, Uri uri, int userId) { 737 if (sVerbose) Slog.v(TAG, "onChange(): uri=" + uri + ", userId=" + userId); 738 synchronized (mLock) { 739 updateCachedServiceLocked(userId); 740 } 741 } 742 } 743} 744