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