AutofillManagerService.java revision fe9a53bc45fd0124a876dc0a49680aaf86641d3e
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.Manifest; 27import android.annotation.NonNull; 28import android.app.ActivityManagerInternal; 29import android.content.BroadcastReceiver; 30import android.content.ContentResolver; 31import android.content.Context; 32import android.content.Intent; 33import android.content.IntentFilter; 34import android.content.pm.PackageManager; 35import android.content.pm.UserInfo; 36import android.database.ContentObserver; 37import android.graphics.Rect; 38import android.net.Uri; 39import android.os.Binder; 40import android.os.Bundle; 41import android.os.Handler; 42import android.os.IBinder; 43import android.os.RemoteException; 44import android.os.ResultReceiver; 45import android.os.ShellCallback; 46import android.os.UserHandle; 47import android.os.UserManager; 48import android.os.UserManagerInternal; 49import android.provider.Settings; 50import android.util.LocalLog; 51import android.util.Log; 52import android.util.Slog; 53import android.util.SparseArray; 54import android.util.SparseBooleanArray; 55import android.view.autofill.AutofillId; 56import android.view.autofill.AutofillValue; 57import android.view.autofill.IAutoFillManager; 58import android.view.autofill.IAutoFillManagerClient; 59 60import com.android.internal.annotations.GuardedBy; 61import com.android.internal.os.BackgroundThread; 62import com.android.internal.os.IResultReceiver; 63import com.android.internal.util.DumpUtils; 64import com.android.internal.util.Preconditions; 65import com.android.server.FgThread; 66import com.android.server.LocalServices; 67import com.android.server.SystemService; 68import com.android.server.autofill.ui.AutoFillUI; 69 70import java.io.FileDescriptor; 71import java.io.PrintWriter; 72import java.util.ArrayList; 73import java.util.List; 74 75/** 76 * Entry point service for autofill management. 77 * 78 * <p>This service provides the {@link IAutoFillManager} implementation and keeps a list of 79 * {@link AutofillManagerServiceImpl} per user; the real work is done by 80 * {@link AutofillManagerServiceImpl} itself. 81 */ 82// TODO(b/33197203): Handle removing of packages 83public final class AutofillManagerService extends SystemService { 84 85 private static final String TAG = "AutofillManagerService"; 86 87 static final String RECEIVER_BUNDLE_EXTRA_SESSIONS = "sessions"; 88 89 private final Context mContext; 90 private final AutoFillUI mUi; 91 92 private final Object mLock = new Object(); 93 94 /** 95 * Cache of {@link AutofillManagerServiceImpl} per user id. 96 * <p> 97 * It has to be mapped by user id because the same current user could have simultaneous sessions 98 * associated to different user profiles (for example, in a multi-window environment or when 99 * device has work profiles). 100 */ 101 @GuardedBy("mLock") 102 private SparseArray<AutofillManagerServiceImpl> mServicesCache = new SparseArray<>(); 103 104 /** 105 * Users disabled due to {@link UserManager} restrictions. 106 */ 107 @GuardedBy("mLock") 108 private final SparseBooleanArray mDisabledUsers = new SparseBooleanArray(); 109 110 // TODO(b/33197203): set a different max (or disable it) on low-memory devices. 111 private final LocalLog mRequestsHistory = new LocalLog(20); 112 113 // TODO(b/33197203): is this still needed? 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 onStopUser(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 AutofillManagerServiceImpl service = mServicesCache.get(userId); 200 if (service == null) { 201 service = new AutofillManagerServiceImpl(mContext, mLock, 202 mRequestsHistory, userId, mUi, mDisabledUsers.get(userId)); 203 mServicesCache.put(userId, service); 204 } 205 return service; 206 } 207 208 // Called by Shell command. 209 void requestSaveForUser(int userId) { 210 Slog.i(TAG, "requestSaveForUser(): " + userId); 211 mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG); 212 final IBinder activityToken = getTopActivityForUser(); 213 if (activityToken != null) { 214 synchronized (mLock) { 215 final AutofillManagerServiceImpl service = mServicesCache.get(userId); 216 if (service == null) { 217 Log.w(TAG, "handleSaveForUser(): no cached service for userId " + userId); 218 return; 219 } 220 221 service.requestSaveForUserLocked(activityToken); 222 } 223 } 224 } 225 226 // Called by Shell command. 227 void destroySessions(int userId, IResultReceiver receiver) { 228 Slog.i(TAG, "destroySessions() for userId " + userId); 229 mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG); 230 231 synchronized (mLock) { 232 if (userId != UserHandle.USER_ALL) { 233 mServicesCache.get(userId).destroySessionsLocked(); 234 } else { 235 final int size = mServicesCache.size(); 236 for (int i = 0; i < size; i++) { 237 mServicesCache.valueAt(i).destroySessionsLocked(); 238 } 239 } 240 } 241 242 try { 243 receiver.send(0, new Bundle()); 244 } catch (RemoteException e) { 245 // Just ignore it... 246 } 247 } 248 249 // Called by Shell command. 250 void listSessions(int userId, IResultReceiver receiver) { 251 Slog.i(TAG, "listSessions() for userId " + userId); 252 mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG); 253 final Bundle resultData = new Bundle(); 254 final ArrayList<String> sessions = new ArrayList<>(); 255 256 synchronized (mLock) { 257 if (userId != UserHandle.USER_ALL) { 258 mServicesCache.get(userId).listSessionsLocked(sessions); 259 } else { 260 final int size = mServicesCache.size(); 261 for (int i = 0; i < size; i++) { 262 mServicesCache.valueAt(i).listSessionsLocked(sessions); 263 } 264 } 265 } 266 267 resultData.putStringArrayList(RECEIVER_BUNDLE_EXTRA_SESSIONS, sessions); 268 try { 269 receiver.send(0, resultData); 270 } catch (RemoteException e) { 271 // Just ignore it... 272 } 273 } 274 275 // Called by Shell command. 276 void reset() { 277 Slog.i(TAG, "reset()"); 278 mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG); 279 synchronized (mLock) { 280 final int size = mServicesCache.size(); 281 for (int i = 0; i < size; i++) { 282 mServicesCache.valueAt(i).destroyLocked(); 283 } 284 mServicesCache.clear(); 285 } 286 } 287 288 // Called by Shell command. 289 public void setSaveTimeout(int timeout) { 290 Slog.i(TAG, "setSaveTimeout(" + timeout + ")"); 291 mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG); 292 mUi.setSaveTimeout(timeout); 293 } 294 295 /** 296 * Removes a cached service for a given user. 297 */ 298 private void removeCachedServiceLocked(int userId) { 299 final AutofillManagerServiceImpl service = mServicesCache.get(userId); 300 if (service != null) { 301 mServicesCache.delete(userId); 302 service.destroyLocked(); 303 } 304 } 305 306 /** 307 * Updates a cached service for a given user. 308 */ 309 private void updateCachedServiceLocked(int userId) { 310 updateCachedServiceLocked(userId, mDisabledUsers.get(userId)); 311 } 312 313 /** 314 * Updates a cached service for a given user. 315 */ 316 private void updateCachedServiceLocked(int userId, boolean disabled) { 317 AutofillManagerServiceImpl service = mServicesCache.get(userId); 318 if (service != null) { 319 service.updateLocked(disabled); 320 } 321 } 322 323 private IBinder getTopActivityForUser() { 324 final List<IBinder> topActivities = LocalServices 325 .getService(ActivityManagerInternal.class).getTopVisibleActivities(); 326 if (VERBOSE) { 327 Slog.v(TAG, "Top activities (" + topActivities.size() + "): " + topActivities); 328 } 329 if (topActivities.isEmpty()) { 330 Slog.w(TAG, "Could not get top activity"); 331 return null; 332 } 333 return topActivities.get(0); 334 } 335 336 final class AutoFillManagerServiceStub extends IAutoFillManager.Stub { 337 @Override 338 public boolean addClient(IAutoFillManagerClient client, int userId) { 339 synchronized (mLock) { 340 return getServiceForUserLocked(userId).addClientLocked(client); 341 } 342 } 343 344 @Override 345 public void setAuthenticationResult(Bundle data, IBinder activityToken, int userId) { 346 synchronized (mLock) { 347 final AutofillManagerServiceImpl service = getServiceForUserLocked(userId); 348 service.setAuthenticationResultLocked(data, activityToken); 349 } 350 } 351 352 @Override 353 public void setHasCallback(IBinder activityToken, int userId, boolean hasIt) { 354 synchronized (mLock) { 355 final AutofillManagerServiceImpl service = getServiceForUserLocked(userId); 356 service.setHasCallback(activityToken, hasIt); 357 } 358 } 359 360 @Override 361 public void startSession(IBinder activityToken, IBinder windowToken, IBinder appCallback, 362 AutofillId autofillId, Rect bounds, AutofillValue value, int userId, 363 boolean hasCallback, int flags, String packageName) { 364 // TODO(b/33197203): make sure it's called by resumed / focused activity 365 366 activityToken = Preconditions.checkNotNull(activityToken, "activityToken"); 367 appCallback = Preconditions.checkNotNull(appCallback, "appCallback"); 368 autofillId = Preconditions.checkNotNull(autofillId, "autoFillId"); 369 packageName = Preconditions.checkNotNull(packageName, "packageName"); 370 371 Preconditions.checkArgument(userId == UserHandle.getUserId(getCallingUid()), "userId"); 372 373 try { 374 mContext.getPackageManager().getPackageInfoAsUser(packageName, 0, userId); 375 } catch (PackageManager.NameNotFoundException e) { 376 throw new IllegalArgumentException(packageName + " is not a valid package", e); 377 } 378 379 synchronized (mLock) { 380 final AutofillManagerServiceImpl service = getServiceForUserLocked(userId); 381 service.startSessionLocked(activityToken, windowToken, appCallback, 382 autofillId, bounds, value, hasCallback, flags, packageName); 383 } 384 } 385 386 @Override 387 public void updateSession(IBinder activityToken, AutofillId id, Rect bounds, 388 AutofillValue value, int flags, int userId) { 389 synchronized (mLock) { 390 final AutofillManagerServiceImpl service = mServicesCache.get( 391 UserHandle.getCallingUserId()); 392 if (service != null) { 393 service.updateSessionLocked(activityToken, id, bounds, value, flags); 394 } 395 } 396 } 397 398 @Override 399 public void finishSession(IBinder activityToken, int userId) { 400 synchronized (mLock) { 401 final AutofillManagerServiceImpl service = mServicesCache.get( 402 UserHandle.getCallingUserId()); 403 if (service != null) { 404 service.finishSessionLocked(activityToken); 405 } 406 } 407 } 408 409 @Override 410 public void cancelSession(IBinder activityToken, int userId) { 411 synchronized (mLock) { 412 final AutofillManagerServiceImpl service = mServicesCache.get( 413 UserHandle.getCallingUserId()); 414 if (service != null) { 415 service.cancelSessionLocked(activityToken); 416 } 417 } 418 } 419 420 @Override 421 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 422 if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return; 423 synchronized (mLock) { 424 pw.print("Disabled users: "); pw.println(mDisabledUsers); 425 final int size = mServicesCache.size(); 426 pw.print("Cached services: "); 427 if (size == 0) { 428 pw.println("none"); 429 } else { 430 pw.println(size); 431 for (int i = 0; i < size; i++) { 432 pw.print("\nService at index "); pw.println(i); 433 final AutofillManagerServiceImpl impl = mServicesCache.valueAt(i); 434 impl.dumpLocked(" ", pw); 435 } 436 } 437 mUi.dump(pw); 438 } 439 pw.println("Requests history:"); 440 mRequestsHistory.reverseDump(fd, pw, args); 441 } 442 443 @Override 444 public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err, 445 String[] args, ShellCallback callback, ResultReceiver resultReceiver) { 446 (new AutofillManagerServiceShellCommand(AutofillManagerService.this)).exec( 447 this, in, out, err, args, callback, resultReceiver); 448 } 449 } 450 451 private final class SettingsObserver extends ContentObserver { 452 SettingsObserver(Handler handler) { 453 super(handler); 454 ContentResolver resolver = mContext.getContentResolver(); 455 resolver.registerContentObserver(Settings.Secure.getUriFor( 456 Settings.Secure.AUTOFILL_SERVICE), false, this, UserHandle.USER_ALL); 457 } 458 459 @Override 460 public void onChange(boolean selfChange, Uri uri, int userId) { 461 synchronized (mLock) { 462 updateCachedServiceLocked(userId); 463 } 464 } 465 } 466} 467