AutofillManagerService.java revision bb81092a31649b4e1031e24d68958180f5d4024e
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.DEBUG; 23import static com.android.server.autofill.Helper.VERBOSE; 24import static com.android.server.autofill.Helper.bundleToString; 25 26import android.annotation.NonNull; 27import android.annotation.Nullable; 28import android.app.ActivityManager; 29import android.app.ActivityManagerInternal; 30import android.content.BroadcastReceiver; 31import android.content.ContentResolver; 32import android.content.Context; 33import android.content.Intent; 34import android.content.IntentFilter; 35import android.content.pm.PackageManager; 36import android.content.pm.UserInfo; 37import android.database.ContentObserver; 38import android.graphics.Rect; 39import android.net.Uri; 40import android.os.Binder; 41import android.os.Bundle; 42import android.os.Handler; 43import android.os.IBinder; 44import android.os.RemoteException; 45import android.os.ResultReceiver; 46import android.os.ShellCallback; 47import android.os.UserHandle; 48import android.os.UserManager; 49import android.os.UserManagerInternal; 50import android.provider.Settings; 51import android.service.autofill.FillEventHistory; 52import android.util.LocalLog; 53import android.util.Log; 54import android.util.Slog; 55import android.util.SparseArray; 56import android.util.SparseBooleanArray; 57import android.view.autofill.AutofillId; 58import android.view.autofill.AutofillValue; 59import android.view.autofill.IAutoFillManager; 60import android.view.autofill.IAutoFillManagerClient; 61 62import com.android.internal.annotations.GuardedBy; 63import com.android.internal.os.BackgroundThread; 64import com.android.internal.os.IResultReceiver; 65import com.android.internal.util.DumpUtils; 66import com.android.internal.util.Preconditions; 67import com.android.server.FgThread; 68import com.android.server.LocalServices; 69import com.android.server.SystemService; 70import com.android.server.autofill.ui.AutoFillUI; 71 72import java.io.FileDescriptor; 73import java.io.PrintWriter; 74import java.util.ArrayList; 75import java.util.List; 76import java.util.Objects; 77 78/** 79 * Entry point service for autofill management. 80 * 81 * <p>This service provides the {@link IAutoFillManager} implementation and keeps a list of 82 * {@link AutofillManagerServiceImpl} per user; the real work is done by 83 * {@link AutofillManagerServiceImpl} itself. 84 */ 85public final class AutofillManagerService extends SystemService { 86 87 private static final String TAG = "AutofillManagerService"; 88 89 static final String RECEIVER_BUNDLE_EXTRA_SESSIONS = "sessions"; 90 91 private final Context mContext; 92 private final AutoFillUI mUi; 93 94 private final Object mLock = new Object(); 95 96 /** 97 * Cache of {@link AutofillManagerServiceImpl} per user id. 98 * <p> 99 * It has to be mapped by user id because the same current user could have simultaneous sessions 100 * associated to different user profiles (for example, in a multi-window environment or when 101 * device has work profiles). 102 */ 103 @GuardedBy("mLock") 104 private SparseArray<AutofillManagerServiceImpl> mServicesCache = new SparseArray<>(); 105 106 /** 107 * Users disabled due to {@link UserManager} restrictions. 108 */ 109 @GuardedBy("mLock") 110 private final SparseBooleanArray mDisabledUsers = new SparseBooleanArray(); 111 112 private final LocalLog mRequestsHistory = new LocalLog(20); 113 114 private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { 115 @Override 116 public void onReceive(Context context, Intent intent) { 117 if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(intent.getAction())) { 118 final String reason = intent.getStringExtra("reason"); 119 if (VERBOSE) { 120 Slog.v(TAG, "close system dialogs: " + reason); 121 } 122 mUi.hideAll(); 123 } 124 } 125 }; 126 127 public AutofillManagerService(Context context) { 128 super(context); 129 mContext = context; 130 mUi = new AutoFillUI(mContext); 131 132 final IntentFilter filter = new IntentFilter(); 133 filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS); 134 mContext.registerReceiver(mBroadcastReceiver, filter, null, FgThread.getHandler()); 135 136 // Hookup with UserManager to disable service when necessary. 137 final UserManager um = context.getSystemService(UserManager.class); 138 final UserManagerInternal umi = LocalServices.getService(UserManagerInternal.class); 139 final List<UserInfo> users = um.getUsers(); 140 for (int i = 0; i < users.size(); i++) { 141 final int userId = users.get(i).id; 142 final boolean disabled = umi.getUserRestriction(userId, UserManager.DISALLOW_AUTOFILL); 143 if (disabled) { 144 mDisabledUsers.put(userId, disabled); 145 } 146 } 147 umi.addUserRestrictionsListener((userId, newRestrictions, prevRestrictions) -> { 148 final boolean disabledNow = 149 newRestrictions.getBoolean(UserManager.DISALLOW_AUTOFILL, false); 150 synchronized (mLock) { 151 final boolean disabledBefore = mDisabledUsers.get(userId); 152 if (disabledBefore == disabledNow) { 153 // Nothing changed, do nothing. 154 if (DEBUG) { 155 Slog.d(TAG, "Restriction not changed for user " + userId + ": " 156 + bundleToString(newRestrictions)); 157 return; 158 } 159 } 160 mDisabledUsers.put(userId, disabledNow); 161 updateCachedServiceLocked(userId, disabledNow); 162 } 163 }); 164 } 165 166 @Override 167 public void onStart() { 168 publishBinderService(AUTOFILL_MANAGER_SERVICE, new AutoFillManagerServiceStub()); 169 } 170 171 @Override 172 public void onBootPhase(int phase) { 173 if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) { 174 new SettingsObserver(BackgroundThread.getHandler()); 175 } 176 } 177 178 @Override 179 public void onUnlockUser(int userId) { 180 synchronized (mLock) { 181 updateCachedServiceLocked(userId); 182 } 183 } 184 185 @Override 186 public void onCleanupUser(int userId) { 187 synchronized (mLock) { 188 removeCachedServiceLocked(userId); 189 } 190 } 191 192 /** 193 * Gets the service instance for an user. 194 * 195 * @return service instance. 196 */ 197 @NonNull 198 AutofillManagerServiceImpl getServiceForUserLocked(int userId) { 199 final int resolvedUserId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), 200 Binder.getCallingUid(), userId, false, false, null, null); 201 AutofillManagerServiceImpl service = mServicesCache.get(resolvedUserId); 202 if (service == null) { 203 service = new AutofillManagerServiceImpl(mContext, mLock, mRequestsHistory, 204 resolvedUserId, mUi, mDisabledUsers.get(resolvedUserId)); 205 mServicesCache.put(userId, service); 206 } 207 return service; 208 } 209 210 /** 211 * Peeks the service instance for a user. 212 * 213 * @return service instance or {@code null} if not already present 214 */ 215 @Nullable 216 AutofillManagerServiceImpl peekServiceForUserLocked(int userId) { 217 final int resolvedUserId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), 218 Binder.getCallingUid(), userId, false, false, null, null); 219 return mServicesCache.get(resolvedUserId); 220 } 221 222 // Called by Shell command. 223 void destroySessions(int userId, IResultReceiver receiver) { 224 Slog.i(TAG, "destroySessions() for userId " + userId); 225 mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG); 226 227 synchronized (mLock) { 228 if (userId != UserHandle.USER_ALL) { 229 AutofillManagerServiceImpl service = peekServiceForUserLocked(userId); 230 if (service != null) { 231 service.destroySessionsLocked(); 232 } 233 } else { 234 final int size = mServicesCache.size(); 235 for (int i = 0; i < size; i++) { 236 mServicesCache.valueAt(i).destroySessionsLocked(); 237 } 238 } 239 } 240 241 try { 242 receiver.send(0, new Bundle()); 243 } catch (RemoteException e) { 244 // Just ignore it... 245 } 246 } 247 248 // Called by Shell command. 249 void listSessions(int userId, IResultReceiver receiver) { 250 Slog.i(TAG, "listSessions() for userId " + userId); 251 mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG); 252 final Bundle resultData = new Bundle(); 253 final ArrayList<String> sessions = new ArrayList<>(); 254 255 synchronized (mLock) { 256 if (userId != UserHandle.USER_ALL) { 257 AutofillManagerServiceImpl service = peekServiceForUserLocked(userId); 258 if (service != null) { 259 service.listSessionsLocked(sessions); 260 } 261 } else { 262 final int size = mServicesCache.size(); 263 for (int i = 0; i < size; i++) { 264 mServicesCache.valueAt(i).listSessionsLocked(sessions); 265 } 266 } 267 } 268 269 resultData.putStringArrayList(RECEIVER_BUNDLE_EXTRA_SESSIONS, sessions); 270 try { 271 receiver.send(0, resultData); 272 } catch (RemoteException e) { 273 // Just ignore it... 274 } 275 } 276 277 // Called by Shell command. 278 void reset() { 279 Slog.i(TAG, "reset()"); 280 mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG); 281 synchronized (mLock) { 282 final int size = mServicesCache.size(); 283 for (int i = 0; i < size; i++) { 284 mServicesCache.valueAt(i).destroyLocked(); 285 } 286 mServicesCache.clear(); 287 } 288 } 289 290 /** 291 * Removes a cached service for a given user. 292 */ 293 private void removeCachedServiceLocked(int userId) { 294 final AutofillManagerServiceImpl service = peekServiceForUserLocked(userId); 295 if (service != null) { 296 mServicesCache.delete(userId); 297 service.destroyLocked(); 298 } 299 } 300 301 /** 302 * Updates a cached service for a given user. 303 */ 304 private void updateCachedServiceLocked(int userId) { 305 updateCachedServiceLocked(userId, mDisabledUsers.get(userId)); 306 } 307 308 /** 309 * Updates a cached service for a given user. 310 */ 311 private void updateCachedServiceLocked(int userId, boolean disabled) { 312 AutofillManagerServiceImpl service = peekServiceForUserLocked(userId); 313 if (service != null) { 314 service.updateLocked(disabled); 315 } 316 } 317 318 private IBinder getTopActivityForUser() { 319 final List<IBinder> topActivities = LocalServices 320 .getService(ActivityManagerInternal.class).getTopVisibleActivities(); 321 if (VERBOSE) { 322 Slog.v(TAG, "Top activities (" + topActivities.size() + "): " + topActivities); 323 } 324 if (topActivities.isEmpty()) { 325 Slog.w(TAG, "Could not get top activity"); 326 return null; 327 } 328 return topActivities.get(0); 329 } 330 331 final class AutoFillManagerServiceStub extends IAutoFillManager.Stub { 332 @Override 333 public boolean addClient(IAutoFillManagerClient client, int userId) { 334 synchronized (mLock) { 335 return getServiceForUserLocked(userId).addClientLocked(client); 336 } 337 } 338 339 @Override 340 public void setAuthenticationResult(Bundle data, int sessionId, int userId) { 341 synchronized (mLock) { 342 final AutofillManagerServiceImpl service = getServiceForUserLocked(userId); 343 service.setAuthenticationResultLocked(data, sessionId, getCallingUid()); 344 } 345 } 346 347 @Override 348 public void setHasCallback(int sessionId, int userId, boolean hasIt) { 349 synchronized (mLock) { 350 final AutofillManagerServiceImpl service = getServiceForUserLocked(userId); 351 service.setHasCallback(sessionId, getCallingUid(), hasIt); 352 } 353 } 354 355 @Override 356 public int startSession(IBinder activityToken, IBinder windowToken, IBinder appCallback, 357 AutofillId autofillId, Rect bounds, AutofillValue value, int userId, 358 boolean hasCallback, int flags, String packageName) { 359 360 activityToken = Preconditions.checkNotNull(activityToken, "activityToken"); 361 appCallback = Preconditions.checkNotNull(appCallback, "appCallback"); 362 autofillId = Preconditions.checkNotNull(autofillId, "autoFillId"); 363 packageName = Preconditions.checkNotNull(packageName, "packageName"); 364 365 Preconditions.checkArgument(userId == UserHandle.getUserId(getCallingUid()), "userId"); 366 367 try { 368 mContext.getPackageManager().getPackageInfoAsUser(packageName, 0, userId); 369 } catch (PackageManager.NameNotFoundException e) { 370 throw new IllegalArgumentException(packageName + " is not a valid package", e); 371 } 372 373 synchronized (mLock) { 374 final AutofillManagerServiceImpl service = getServiceForUserLocked(userId); 375 return service.startSessionLocked(activityToken, getCallingUid(), windowToken, 376 appCallback, autofillId, bounds, value, hasCallback, flags, packageName); 377 } 378 } 379 380 @Override 381 public FillEventHistory getFillEventHistory() throws RemoteException { 382 UserHandle user = getCallingUserHandle(); 383 int uid = getCallingUid(); 384 385 synchronized (mLock) { 386 AutofillManagerServiceImpl service = peekServiceForUserLocked(user.getIdentifier()); 387 if (service != null) { 388 return service.getFillEventHistory(uid); 389 } 390 } 391 392 return null; 393 } 394 395 @Override 396 public boolean restoreSession(int sessionId, IBinder activityToken, IBinder appCallback) 397 throws RemoteException { 398 activityToken = Preconditions.checkNotNull(activityToken, "activityToken"); 399 appCallback = Preconditions.checkNotNull(appCallback, "appCallback"); 400 401 synchronized (mLock) { 402 final AutofillManagerServiceImpl service = mServicesCache.get( 403 UserHandle.getCallingUserId()); 404 if (service != null) { 405 return service.restoreSession(sessionId, getCallingUid(), activityToken, 406 appCallback); 407 } 408 } 409 410 return false; 411 } 412 413 @Override 414 public void setWindow(int sessionId, IBinder windowToken) throws RemoteException { 415 windowToken = Preconditions.checkNotNull(windowToken, "windowToken"); 416 417 synchronized (mLock) { 418 final AutofillManagerServiceImpl service = mServicesCache.get( 419 UserHandle.getCallingUserId()); 420 if (service != null) { 421 service.setWindow(sessionId, getCallingUid(), windowToken); 422 } 423 } 424 } 425 426 @Override 427 public void updateSession(int sessionId, AutofillId id, Rect bounds, 428 AutofillValue value, int flags, int userId) { 429 synchronized (mLock) { 430 final AutofillManagerServiceImpl service = peekServiceForUserLocked(userId); 431 if (service != null) { 432 service.updateSessionLocked(sessionId, getCallingUid(), id, bounds, value, 433 flags); 434 } 435 } 436 } 437 438 @Override 439 public void finishSession(int sessionId, int userId) { 440 synchronized (mLock) { 441 final AutofillManagerServiceImpl service = peekServiceForUserLocked(userId); 442 if (service != null) { 443 service.finishSessionLocked(sessionId, getCallingUid()); 444 } 445 } 446 } 447 448 @Override 449 public void cancelSession(int sessionId, int userId) { 450 synchronized (mLock) { 451 final AutofillManagerServiceImpl service = peekServiceForUserLocked(userId); 452 if (service != null) { 453 service.cancelSessionLocked(sessionId, getCallingUid()); 454 } 455 } 456 } 457 458 @Override 459 public void disableOwnedAutofillServices(int userId) { 460 synchronized (mLock) { 461 final AutofillManagerServiceImpl service = peekServiceForUserLocked(userId); 462 if (service != null) { 463 service.disableOwnedAutofillServicesLocked(Binder.getCallingUid()); 464 } 465 } 466 } 467 468 @Override 469 public boolean isServiceSupported(int userId) { 470 synchronized (mLock) { 471 return !mDisabledUsers.get(userId); 472 } 473 } 474 475 @Override 476 public boolean isServiceEnabled(int userId, String packageName) { 477 synchronized (mLock) { 478 final AutofillManagerServiceImpl service = peekServiceForUserLocked(userId); 479 if (service == null) return false; 480 return Objects.equals(packageName, service.getPackageName()); 481 } 482 } 483 484 @Override 485 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 486 if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return; 487 synchronized (mLock) { 488 pw.print("Disabled users: "); pw.println(mDisabledUsers); 489 final int size = mServicesCache.size(); 490 pw.print("Cached services: "); 491 if (size == 0) { 492 pw.println("none"); 493 } else { 494 pw.println(size); 495 for (int i = 0; i < size; i++) { 496 pw.print("\nService at index "); pw.println(i); 497 final AutofillManagerServiceImpl impl = mServicesCache.valueAt(i); 498 impl.dumpLocked(" ", pw); 499 } 500 } 501 mUi.dump(pw); 502 } 503 pw.println("Requests history:"); 504 mRequestsHistory.reverseDump(fd, pw, args); 505 } 506 507 @Override 508 public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err, 509 String[] args, ShellCallback callback, ResultReceiver resultReceiver) { 510 (new AutofillManagerServiceShellCommand(AutofillManagerService.this)).exec( 511 this, in, out, err, args, callback, resultReceiver); 512 } 513 } 514 515 private final class SettingsObserver extends ContentObserver { 516 SettingsObserver(Handler handler) { 517 super(handler); 518 ContentResolver resolver = mContext.getContentResolver(); 519 resolver.registerContentObserver(Settings.Secure.getUriFor( 520 Settings.Secure.AUTOFILL_SERVICE), false, this, UserHandle.USER_ALL); 521 } 522 523 @Override 524 public void onChange(boolean selfChange, Uri uri, int userId) { 525 synchronized (mLock) { 526 updateCachedServiceLocked(userId); 527 } 528 } 529 } 530} 531