AutofillManagerServiceImpl.java revision a9379d0b44ca1f68a0036d2b65218e17fa348514
13659dc62f9e55b1043edb4105c311c8ef997f2aeDake Gu/* 23659dc62f9e55b1043edb4105c311c8ef997f2aeDake Gu * Copyright (C) 2016 The Android Open Source Project 33659dc62f9e55b1043edb4105c311c8ef997f2aeDake Gu * 43659dc62f9e55b1043edb4105c311c8ef997f2aeDake Gu * Licensed under the Apache License, Version 2.0 (the "License"); 53659dc62f9e55b1043edb4105c311c8ef997f2aeDake Gu * you may not use this file except in compliance with the License. 63659dc62f9e55b1043edb4105c311c8ef997f2aeDake Gu * You may obtain a copy of the License at 73659dc62f9e55b1043edb4105c311c8ef997f2aeDake Gu * 83659dc62f9e55b1043edb4105c311c8ef997f2aeDake Gu * http://www.apache.org/licenses/LICENSE-2.0 93659dc62f9e55b1043edb4105c311c8ef997f2aeDake Gu * 103659dc62f9e55b1043edb4105c311c8ef997f2aeDake Gu * Unless required by applicable law or agreed to in writing, software 113659dc62f9e55b1043edb4105c311c8ef997f2aeDake Gu * distributed under the License is distributed on an "AS IS" BASIS, 123659dc62f9e55b1043edb4105c311c8ef997f2aeDake Gu * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 133659dc62f9e55b1043edb4105c311c8ef997f2aeDake Gu * See the License for the specific language governing permissions and 14ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas * limitations under the License. 153659dc62f9e55b1043edb4105c311c8ef997f2aeDake Gu */ 16ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas 1726d09ce0e088ef4c69538ead9e7ee79905a047feDake Gupackage com.android.server.autofill; 183659dc62f9e55b1043edb4105c311c8ef997f2aeDake Gu 193659dc62f9e55b1043edb4105c311c8ef997f2aeDake Guimport static android.view.autofill.AutofillManager.ACTION_START_SESSION; 2026d09ce0e088ef4c69538ead9e7ee79905a047feDake Guimport static android.view.autofill.AutofillManager.NO_SESSION; 213659dc62f9e55b1043edb4105c311c8ef997f2aeDake Gu 223659dc62f9e55b1043edb4105c311c8ef997f2aeDake Guimport static com.android.server.autofill.Helper.sDebug; 238619e0ef7062b6a714f22af993e4b440fae7ef08Aurimas Liutikasimport static com.android.server.autofill.Helper.sVerbose; 248619e0ef7062b6a714f22af993e4b440fae7ef08Aurimas Liutikas 2526d09ce0e088ef4c69538ead9e7ee79905a047feDake Guimport android.annotation.NonNull; 2626d09ce0e088ef4c69538ead9e7ee79905a047feDake Guimport android.annotation.Nullable; 2726d09ce0e088ef4c69538ead9e7ee79905a047feDake Guimport android.app.ActivityManager; 2826d09ce0e088ef4c69538ead9e7ee79905a047feDake Guimport android.app.AppGlobals; 2926d09ce0e088ef4c69538ead9e7ee79905a047feDake Guimport android.app.IActivityManager; 3026d09ce0e088ef4c69538ead9e7ee79905a047feDake Guimport android.content.ComponentName; 3126d09ce0e088ef4c69538ead9e7ee79905a047feDake Guimport android.content.Context; 3226d09ce0e088ef4c69538ead9e7ee79905a047feDake Guimport android.content.pm.ApplicationInfo; 3326d09ce0e088ef4c69538ead9e7ee79905a047feDake Guimport android.content.pm.PackageManager; 3426d09ce0e088ef4c69538ead9e7ee79905a047feDake Guimport android.content.pm.ServiceInfo; 3526d09ce0e088ef4c69538ead9e7ee79905a047feDake Guimport android.graphics.Rect; 3626d09ce0e088ef4c69538ead9e7ee79905a047feDake Guimport android.os.AsyncTask; 373659dc62f9e55b1043edb4105c311c8ef997f2aeDake Guimport android.os.Binder; 38ceb7ab2ddd6e157cd4ade0f14a382c39428163c4Dake Guimport android.os.Bundle; 393659dc62f9e55b1043edb4105c311c8ef997f2aeDake Guimport android.os.IBinder; 403659dc62f9e55b1043edb4105c311c8ef997f2aeDake Guimport android.os.Looper; 413659dc62f9e55b1043edb4105c311c8ef997f2aeDake Guimport android.os.RemoteCallbackList; 42ceb7ab2ddd6e157cd4ade0f14a382c39428163c4Dake Guimport android.os.RemoteException; 433659dc62f9e55b1043edb4105c311c8ef997f2aeDake Guimport android.os.UserHandle; 443659dc62f9e55b1043edb4105c311c8ef997f2aeDake Guimport android.os.UserManager; 453659dc62f9e55b1043edb4105c311c8ef997f2aeDake Guimport android.provider.Settings; 46ceb7ab2ddd6e157cd4ade0f14a382c39428163c4Dake Guimport android.service.autofill.AutofillService; 473659dc62f9e55b1043edb4105c311c8ef997f2aeDake Guimport android.service.autofill.AutofillServiceInfo; 483659dc62f9e55b1043edb4105c311c8ef997f2aeDake Guimport android.service.autofill.FillEventHistory; 493659dc62f9e55b1043edb4105c311c8ef997f2aeDake Guimport android.service.autofill.FillEventHistory.Event; 503659dc62f9e55b1043edb4105c311c8ef997f2aeDake Guimport android.service.autofill.FillResponse; 51a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stoutimport android.service.autofill.IAutoFillService; 523659dc62f9e55b1043edb4105c311c8ef997f2aeDake Guimport android.text.TextUtils; 533659dc62f9e55b1043edb4105c311c8ef997f2aeDake Guimport android.util.ArrayMap; 543659dc62f9e55b1043edb4105c311c8ef997f2aeDake Guimport android.util.LocalLog; 553659dc62f9e55b1043edb4105c311c8ef997f2aeDake Guimport android.util.Slog; 563659dc62f9e55b1043edb4105c311c8ef997f2aeDake Guimport android.util.SparseArray; 5726d09ce0e088ef4c69538ead9e7ee79905a047feDake Guimport android.view.autofill.AutofillId; 5826d09ce0e088ef4c69538ead9e7ee79905a047feDake Guimport android.view.autofill.AutofillValue; 5926d09ce0e088ef4c69538ead9e7ee79905a047feDake Guimport android.view.autofill.IAutoFillManagerClient; 6026d09ce0e088ef4c69538ead9e7ee79905a047feDake Gu 6126d09ce0e088ef4c69538ead9e7ee79905a047feDake Guimport com.android.internal.R; 6226d09ce0e088ef4c69538ead9e7ee79905a047feDake Guimport com.android.internal.annotations.GuardedBy; 6326d09ce0e088ef4c69538ead9e7ee79905a047feDake Guimport com.android.internal.os.HandlerCaller; 6426d09ce0e088ef4c69538ead9e7ee79905a047feDake Guimport com.android.server.autofill.ui.AutoFillUI; 6526d09ce0e088ef4c69538ead9e7ee79905a047feDake Gu 6626d09ce0e088ef4c69538ead9e7ee79905a047feDake Guimport java.io.PrintWriter; 6726d09ce0e088ef4c69538ead9e7ee79905a047feDake Guimport java.util.ArrayList; 6826d09ce0e088ef4c69538ead9e7ee79905a047feDake Guimport java.util.Random; 6926d09ce0e088ef4c69538ead9e7ee79905a047feDake Gu 7026d09ce0e088ef4c69538ead9e7ee79905a047feDake Gu/** 7126d09ce0e088ef4c69538ead9e7ee79905a047feDake Gu * Bridge between the {@code system_server}'s {@link AutofillManagerService} and the 7226d09ce0e088ef4c69538ead9e7ee79905a047feDake Gu * app's {@link IAutoFillService} implementation. 7326d09ce0e088ef4c69538ead9e7ee79905a047feDake Gu * 7426d09ce0e088ef4c69538ead9e7ee79905a047feDake Gu */ 7526d09ce0e088ef4c69538ead9e7ee79905a047feDake Gufinal class AutofillManagerServiceImpl { 7626d09ce0e088ef4c69538ead9e7ee79905a047feDake Gu 7726d09ce0e088ef4c69538ead9e7ee79905a047feDake Gu private static final String TAG = "AutofillManagerServiceImpl"; 7826d09ce0e088ef4c69538ead9e7ee79905a047feDake Gu private static final int MAX_SESSION_ID_CREATE_TRIES = 2048; 7926d09ce0e088ef4c69538ead9e7ee79905a047feDake Gu 8026d09ce0e088ef4c69538ead9e7ee79905a047feDake Gu /** Minimum interval to prune abandoned sessions */ 8126d09ce0e088ef4c69538ead9e7ee79905a047feDake Gu private static final int MAX_ABANDONED_SESSION_MILLIS = 30000; 8226d09ce0e088ef4c69538ead9e7ee79905a047feDake Gu 8326d09ce0e088ef4c69538ead9e7ee79905a047feDake Gu static final int MSG_SERVICE_SAVE = 1; 8426d09ce0e088ef4c69538ead9e7ee79905a047feDake Gu 8526d09ce0e088ef4c69538ead9e7ee79905a047feDake Gu private final int mUserId; 8626d09ce0e088ef4c69538ead9e7ee79905a047feDake Gu private final Context mContext; 8726d09ce0e088ef4c69538ead9e7ee79905a047feDake Gu private final Object mLock; 8826d09ce0e088ef4c69538ead9e7ee79905a047feDake Gu private final AutoFillUI mUi; 8926d09ce0e088ef4c69538ead9e7ee79905a047feDake Gu 9026d09ce0e088ef4c69538ead9e7ee79905a047feDake Gu private RemoteCallbackList<IAutoFillManagerClient> mClients; 9126d09ce0e088ef4c69538ead9e7ee79905a047feDake Gu private AutofillServiceInfo mInfo; 9226d09ce0e088ef4c69538ead9e7ee79905a047feDake Gu 9326d09ce0e088ef4c69538ead9e7ee79905a047feDake Gu private static final Random sRandom = new Random(); 9426d09ce0e088ef4c69538ead9e7ee79905a047feDake Gu 9526d09ce0e088ef4c69538ead9e7ee79905a047feDake Gu private final LocalLog mRequestsHistory; 9626d09ce0e088ef4c69538ead9e7ee79905a047feDake Gu /** 9726d09ce0e088ef4c69538ead9e7ee79905a047feDake Gu * Whether service was disabled for user due to {@link UserManager} restrictions. 9826d09ce0e088ef4c69538ead9e7ee79905a047feDake Gu */ 9926d09ce0e088ef4c69538ead9e7ee79905a047feDake Gu private boolean mDisabled; 10026d09ce0e088ef4c69538ead9e7ee79905a047feDake Gu 10126d09ce0e088ef4c69538ead9e7ee79905a047feDake Gu private final HandlerCaller.Callback mHandlerCallback = (msg) -> { 10226d09ce0e088ef4c69538ead9e7ee79905a047feDake Gu switch (msg.what) { 10326d09ce0e088ef4c69538ead9e7ee79905a047feDake Gu case MSG_SERVICE_SAVE: 10426d09ce0e088ef4c69538ead9e7ee79905a047feDake Gu handleSessionSave(msg.arg1); 10526d09ce0e088ef4c69538ead9e7ee79905a047feDake Gu break; 10626d09ce0e088ef4c69538ead9e7ee79905a047feDake Gu default: 10726d09ce0e088ef4c69538ead9e7ee79905a047feDake Gu Slog.w(TAG, "invalid msg on handler: " + msg); 10826d09ce0e088ef4c69538ead9e7ee79905a047feDake Gu } 10926d09ce0e088ef4c69538ead9e7ee79905a047feDake Gu }; 11026d09ce0e088ef4c69538ead9e7ee79905a047feDake Gu 11126d09ce0e088ef4c69538ead9e7ee79905a047feDake Gu private final HandlerCaller mHandlerCaller = new HandlerCaller(null, Looper.getMainLooper(), 11226d09ce0e088ef4c69538ead9e7ee79905a047feDake Gu mHandlerCallback, true); 1133659dc62f9e55b1043edb4105c311c8ef997f2aeDake Gu 114 /** 115 * Cache of pending {@link Session}s, keyed by sessionId. 116 * 117 * <p>They're kept until the {@link AutofillService} finished handling a request, an error 118 * occurs, or the session is abandoned. 119 */ 120 @GuardedBy("mLock") 121 private final SparseArray<Session> mSessions = new SparseArray<>(); 122 123 /** The last selection */ 124 @GuardedBy("mLock") 125 private FillEventHistory mEventHistory; 126 127 /** When was {@link PruneTask} last executed? */ 128 private long mLastPrune = 0; 129 130 AutofillManagerServiceImpl(Context context, Object lock, LocalLog requestsHistory, 131 int userId, AutoFillUI ui, boolean disabled) { 132 mContext = context; 133 mLock = lock; 134 mRequestsHistory = requestsHistory; 135 mUserId = userId; 136 mUi = ui; 137 updateLocked(disabled); 138 } 139 140 CharSequence getServiceName() { 141 final String packageName = getPackageName(); 142 if (packageName == null) { 143 return null; 144 } 145 146 try { 147 final PackageManager pm = mContext.getPackageManager(); 148 final ApplicationInfo info = pm.getApplicationInfo(packageName, 0); 149 return pm.getApplicationLabel(info); 150 } catch (Exception e) { 151 Slog.e(TAG, "Could not get label for " + packageName + ": " + e); 152 return packageName; 153 } 154 } 155 156 String getPackageName() { 157 final ComponentName serviceComponent = getServiceComponentName(); 158 if (serviceComponent != null) { 159 return serviceComponent.getPackageName(); 160 } 161 return null; 162 } 163 164 ComponentName getServiceComponentName() { 165 synchronized (mLock) { 166 if (mInfo == null) { 167 return null; 168 } 169 return mInfo.getServiceInfo().getComponentName(); 170 } 171 } 172 173 private String getComponentNameFromSettings() { 174 return Settings.Secure.getStringForUser( 175 mContext.getContentResolver(), Settings.Secure.AUTOFILL_SERVICE, mUserId); 176 } 177 178 void updateLocked(boolean disabled) { 179 final boolean wasEnabled = isEnabled(); 180 mDisabled = disabled; 181 ComponentName serviceComponent = null; 182 ServiceInfo serviceInfo = null; 183 final String componentName = getComponentNameFromSettings(); 184 if (!TextUtils.isEmpty(componentName)) { 185 try { 186 serviceComponent = ComponentName.unflattenFromString(componentName); 187 serviceInfo = AppGlobals.getPackageManager().getServiceInfo(serviceComponent, 188 0, mUserId); 189 } catch (RuntimeException | RemoteException e) { 190 Slog.e(TAG, "Bad autofill service name " + componentName + ": " + e); 191 return; 192 } 193 } 194 try { 195 if (serviceInfo != null) { 196 mInfo = new AutofillServiceInfo(mContext.getPackageManager(), 197 serviceComponent, mUserId); 198 } else { 199 mInfo = null; 200 } 201 if (wasEnabled != isEnabled()) { 202 if (!isEnabled()) { 203 final int sessionCount = mSessions.size(); 204 for (int i = sessionCount - 1; i >= 0; i--) { 205 final Session session = mSessions.valueAt(i); 206 session.removeSelfLocked(); 207 } 208 } 209 sendStateToClients(false); 210 } 211 } catch (Exception e) { 212 Slog.e(TAG, "Bad AutofillService '" + componentName + "': " + e); 213 } 214 } 215 216 /** 217 * Used by {@link AutofillManagerServiceShellCommand} to request save for the current top app. 218 */ 219 void requestSaveForUserLocked(IBinder activityToken) { 220 if (!isEnabled()) { 221 return; 222 } 223 224 final int numSessions = mSessions.size(); 225 for (int i = 0; i < numSessions; i++) { 226 final Session session = mSessions.valueAt(i); 227 if (session.getActivityTokenLocked().equals(activityToken)) { 228 session.callSaveLocked(); 229 return; 230 } 231 } 232 233 Slog.w(TAG, "requestSaveForUserLocked(): no session for " + activityToken); 234 } 235 236 boolean addClientLocked(IAutoFillManagerClient client) { 237 if (mClients == null) { 238 mClients = new RemoteCallbackList<>(); 239 } 240 mClients.register(client); 241 return isEnabled(); 242 } 243 244 void setAuthenticationResultLocked(Bundle data, int sessionId, int authenticationId, int uid) { 245 if (!isEnabled()) { 246 return; 247 } 248 final Session session = mSessions.get(sessionId); 249 if (session != null && uid == session.uid) { 250 session.setAuthenticationResultLocked(data, authenticationId); 251 } 252 } 253 254 void setHasCallback(int sessionId, int uid, boolean hasIt) { 255 if (!isEnabled()) { 256 return; 257 } 258 final Session session = mSessions.get(sessionId); 259 if (session != null && uid == session.uid) { 260 synchronized (mLock) { 261 session.setHasCallbackLocked(hasIt); 262 } 263 } 264 } 265 266 int startSessionLocked(@NonNull IBinder activityToken, int uid, 267 @NonNull IBinder appCallbackToken, @NonNull AutofillId autofillId, 268 @NonNull Rect virtualBounds, @Nullable AutofillValue value, boolean hasCallback, 269 int flags, @NonNull String packageName) { 270 if (!isEnabled()) { 271 return 0; 272 } 273 274 // Occasionally clean up abandoned sessions 275 pruneAbandonedSessionsLocked(); 276 277 final Session newSession = createSessionByTokenLocked(activityToken, uid, appCallbackToken, 278 hasCallback, flags, packageName); 279 if (newSession == null) { 280 return NO_SESSION; 281 } 282 283 final String historyItem = 284 "id=" + newSession.id + " uid=" + uid + " s=" + mInfo.getServiceInfo().packageName 285 + " u=" + mUserId + " i=" + autofillId + " b=" + virtualBounds + " hc=" + 286 hasCallback + " f=" + flags; 287 mRequestsHistory.log(historyItem); 288 289 newSession.updateLocked(autofillId, virtualBounds, value, ACTION_START_SESSION, flags); 290 291 return newSession.id; 292 } 293 294 /** 295 * Remove abandoned sessions if needed. 296 */ 297 private void pruneAbandonedSessionsLocked() { 298 long now = System.currentTimeMillis(); 299 if (mLastPrune < now - MAX_ABANDONED_SESSION_MILLIS) { 300 mLastPrune = now; 301 302 if (mSessions.size() > 0) { 303 (new PruneTask()).execute(); 304 } 305 } 306 } 307 308 void finishSessionLocked(int sessionId, int uid) { 309 if (!isEnabled()) { 310 return; 311 } 312 313 final Session session = mSessions.get(sessionId); 314 if (session == null || uid != session.uid) { 315 if (sVerbose) { 316 Slog.v(TAG, "finishSessionLocked(): no session for " + sessionId + "(" + uid + ")"); 317 } 318 return; 319 } 320 321 final boolean finished = session.showSaveLocked(); 322 if (sVerbose) Slog.v(TAG, "finishSessionLocked(): session finished on save? " + finished); 323 324 if (finished) { 325 session.removeSelfLocked(); 326 } 327 } 328 329 void cancelSessionLocked(int sessionId, int uid) { 330 if (!isEnabled()) { 331 return; 332 } 333 334 final Session session = mSessions.get(sessionId); 335 if (session == null || uid != session.uid) { 336 Slog.w(TAG, "cancelSessionLocked(): no session for " + sessionId + "(" + uid + ")"); 337 return; 338 } 339 session.removeSelfLocked(); 340 } 341 342 void disableOwnedAutofillServicesLocked(int uid) { 343 if (mInfo == null || mInfo.getServiceInfo().applicationInfo.uid 344 != UserHandle.getAppId(uid)) { 345 return; 346 } 347 final long identity = Binder.clearCallingIdentity(); 348 try { 349 final String autoFillService = getComponentNameFromSettings(); 350 if (mInfo.getServiceInfo().getComponentName().equals( 351 ComponentName.unflattenFromString(autoFillService))) { 352 Settings.Secure.putStringForUser(mContext.getContentResolver(), 353 Settings.Secure.AUTOFILL_SERVICE, null, mUserId); 354 destroySessionsLocked(); 355 } 356 } finally { 357 Binder.restoreCallingIdentity(identity); 358 } 359 } 360 361 private Session createSessionByTokenLocked(@NonNull IBinder activityToken, int uid, 362 @NonNull IBinder appCallbackToken, boolean hasCallback, int flags, 363 @NonNull String packageName) { 364 // use random ids so that one app cannot know that another app creates sessions 365 int sessionId; 366 int tries = 0; 367 do { 368 tries++; 369 if (tries > MAX_SESSION_ID_CREATE_TRIES) { 370 Slog.w(TAG, "Cannot create session in " + MAX_SESSION_ID_CREATE_TRIES + " tries"); 371 return null; 372 } 373 374 sessionId = sRandom.nextInt(); 375 } while (sessionId == NO_SESSION || mSessions.indexOfKey(sessionId) >= 0); 376 377 final Session newSession = new Session(this, mUi, mContext, mHandlerCaller, mUserId, mLock, 378 sessionId, uid, activityToken, appCallbackToken, hasCallback, 379 mInfo.getServiceInfo().getComponentName(), packageName); 380 mSessions.put(newSession.id, newSession); 381 382 return newSession; 383 } 384 385 /** 386 * Restores a session after an activity was temporarily destroyed. 387 * 388 * @param sessionId The id of the session to restore 389 * @param uid UID of the process that tries to restore the session 390 * @param activityToken The new instance of the activity 391 * @param appCallback The callbacks to the activity 392 */ 393 boolean restoreSession(int sessionId, int uid, @NonNull IBinder activityToken, 394 @NonNull IBinder appCallback) { 395 final Session session = mSessions.get(sessionId); 396 397 if (session == null || uid != session.uid) { 398 return false; 399 } else { 400 session.switchActivity(activityToken, appCallback); 401 return true; 402 } 403 } 404 405 void updateSessionLocked(int sessionId, int uid, AutofillId autofillId, Rect virtualBounds, 406 AutofillValue value, int action, int flags) { 407 final Session session = mSessions.get(sessionId); 408 if (session == null || session.uid != uid) { 409 if (sVerbose) { 410 Slog.v(TAG, "updateSessionLocked(): session gone for " + sessionId + "(" + uid 411 + ")"); 412 } 413 return; 414 } 415 416 session.updateLocked(autofillId, virtualBounds, value, action, flags); 417 } 418 419 void removeSessionLocked(int sessionId) { 420 mSessions.remove(sessionId); 421 } 422 423 private void handleSessionSave(int sessionId) { 424 synchronized (mLock) { 425 final Session session = mSessions.get(sessionId); 426 if (session == null) { 427 Slog.w(TAG, "handleSessionSave(): already gone: " + sessionId); 428 429 return; 430 } 431 session.callSaveLocked(); 432 } 433 } 434 435 void destroyLocked() { 436 if (sVerbose) Slog.v(TAG, "destroyLocked()"); 437 438 final int numSessions = mSessions.size(); 439 for (int i = 0; i < numSessions; i++) { 440 mSessions.valueAt(i).destroyLocked(); 441 } 442 mSessions.clear(); 443 444 sendStateToClients(true); 445 } 446 447 CharSequence getServiceLabel() { 448 return mInfo.getServiceInfo().loadLabel(mContext.getPackageManager()); 449 } 450 451 /** 452 * Initializes the last fill selection after an autofill service returned a new 453 * {@link FillResponse}. 454 */ 455 void setLastResponse(int serviceUid, @NonNull FillResponse response) { 456 synchronized (mLock) { 457 mEventHistory = new FillEventHistory(serviceUid, response.getClientState()); 458 } 459 } 460 461 /** 462 * Updates the last fill selection when an authentication was selected. 463 */ 464 void setAuthenticationSelected() { 465 synchronized (mLock) { 466 mEventHistory.addEvent(new Event(Event.TYPE_AUTHENTICATION_SELECTED, null)); 467 } 468 } 469 470 /** 471 * Updates the last fill selection when an dataset authentication was selected. 472 */ 473 void setDatasetAuthenticationSelected(@Nullable String selectedDataset) { 474 synchronized (mLock) { 475 mEventHistory.addEvent( 476 new Event(Event.TYPE_DATASET_AUTHENTICATION_SELECTED, selectedDataset)); 477 } 478 } 479 480 /** 481 * Updates the last fill selection when an save Ui is shown. 482 */ 483 void setSaveShown() { 484 synchronized (mLock) { 485 mEventHistory.addEvent(new Event(Event.TYPE_SAVE_SHOWN, null)); 486 } 487 } 488 489 /** 490 * Updates the last fill response when a dataset was selected. 491 */ 492 void setDatasetSelected(@Nullable String selectedDataset) { 493 synchronized (mLock) { 494 mEventHistory.addEvent(new Event(Event.TYPE_DATASET_SELECTED, selectedDataset)); 495 } 496 } 497 498 /** 499 * Gets the fill event history. 500 * 501 * @param callingUid The calling uid 502 * 503 * @return The history or {@code null} if there is none. 504 */ 505 FillEventHistory getFillEventHistory(int callingUid) { 506 synchronized (mLock) { 507 if (mEventHistory != null && mEventHistory.getServiceUid() == callingUid) { 508 return mEventHistory; 509 } 510 } 511 512 return null; 513 } 514 515 void dumpLocked(String prefix, PrintWriter pw) { 516 final String prefix2 = prefix + " "; 517 518 pw.print(prefix); pw.print("User: "); pw.println(mUserId); 519 pw.print(prefix); pw.print("Component: "); pw.println(mInfo != null 520 ? mInfo.getServiceInfo().getComponentName() : null); 521 pw.print(prefix); pw.print("Component from settings: "); 522 pw.println(getComponentNameFromSettings()); 523 pw.print(prefix); pw.print("Default component: "); 524 pw.println(mContext.getString(R.string.config_defaultAutofillService)); 525 pw.print(prefix); pw.print("Disabled: "); pw.println(mDisabled); 526 pw.print(prefix); pw.print("Last prune: "); pw.println(mLastPrune); 527 528 final int size = mSessions.size(); 529 if (size == 0) { 530 pw.print(prefix); pw.println("No sessions"); 531 } else { 532 pw.print(prefix); pw.print(size); pw.println(" sessions:"); 533 for (int i = 0; i < size; i++) { 534 pw.print(prefix); pw.print("#"); pw.println(i + 1); 535 mSessions.valueAt(i).dumpLocked(prefix2, pw); 536 } 537 } 538 539 if (mEventHistory == null || mEventHistory.getEvents() == null 540 || mEventHistory.getEvents().size() == 0) { 541 pw.print(prefix); pw.println("No event on last fill response"); 542 } else { 543 pw.print(prefix); pw.println("Events of last fill response:"); 544 pw.print(prefix); 545 546 int numEvents = mEventHistory.getEvents().size(); 547 for (int i = 0; i < numEvents; i++) { 548 final Event event = mEventHistory.getEvents().get(i); 549 pw.println(" " + i + ": eventType=" + event.getType() + " datasetId=" 550 + event.getDatasetId()); 551 } 552 } 553 } 554 555 void destroySessionsLocked() { 556 while (mSessions.size() > 0) { 557 mSessions.valueAt(0).removeSelfLocked(); 558 } 559 } 560 561 void listSessionsLocked(ArrayList<String> output) { 562 final int numSessions = mSessions.size(); 563 for (int i = 0; i < numSessions; i++) { 564 output.add((mInfo != null ? mInfo.getServiceInfo().getComponentName() 565 : null) + ":" + mSessions.keyAt(i)); 566 } 567 } 568 569 private void sendStateToClients(boolean resetClient) { 570 final RemoteCallbackList<IAutoFillManagerClient> clients; 571 final int userClientCount; 572 synchronized (mLock) { 573 if (mClients == null) { 574 return; 575 } 576 clients = mClients; 577 userClientCount = clients.beginBroadcast(); 578 } 579 try { 580 for (int i = 0; i < userClientCount; i++) { 581 final IAutoFillManagerClient client = clients.getBroadcastItem(i); 582 try { 583 final boolean resetSession; 584 synchronized (mLock) { 585 resetSession = resetClient || isClientSessionDestroyedLocked(client); 586 } 587 client.setState(isEnabled(), resetSession, resetClient); 588 } catch (RemoteException re) { 589 /* ignore */ 590 } 591 } 592 } finally { 593 clients.finishBroadcast(); 594 } 595 } 596 597 private boolean isClientSessionDestroyedLocked(IAutoFillManagerClient client) { 598 final int sessionCount = mSessions.size(); 599 for (int i = 0; i < sessionCount; i++) { 600 final Session session = mSessions.valueAt(i); 601 if (session.getClient().equals(client)) { 602 return session.isDestroyed(); 603 } 604 } 605 return true; 606 } 607 608 boolean isEnabled() { 609 return mInfo != null && !mDisabled; 610 } 611 612 @Override 613 public String toString() { 614 return "AutofillManagerServiceImpl: [userId=" + mUserId 615 + ", component=" + (mInfo != null 616 ? mInfo.getServiceInfo().getComponentName() : null) + "]"; 617 } 618 619 /** Task used to prune abandoned session */ 620 private class PruneTask extends AsyncTask<Void, Void, Void> { 621 @Override 622 protected Void doInBackground(Void... ignored) { 623 int numSessionsToRemove; 624 ArrayMap<IBinder, Integer> sessionsToRemove; 625 626 synchronized (mLock) { 627 numSessionsToRemove = mSessions.size(); 628 sessionsToRemove = new ArrayMap<>(numSessionsToRemove); 629 630 for (int i = 0; i < numSessionsToRemove; i++) { 631 Session session = mSessions.valueAt(i); 632 633 sessionsToRemove.put(session.getActivityTokenLocked(), session.id); 634 } 635 } 636 637 IActivityManager am = ActivityManager.getService(); 638 639 // Only remove sessions which's activities are not known to the activity manager anymore 640 for (int i = 0; i < numSessionsToRemove; i++) { 641 try { 642 // The activity manager cannot resolve activities that have been removed 643 if (am.getActivityClassForToken(sessionsToRemove.keyAt(i)) != null) { 644 sessionsToRemove.removeAt(i); 645 i--; 646 numSessionsToRemove--; 647 } 648 } catch (RemoteException e) { 649 Slog.w(TAG, "Cannot figure out if activity is finished", e); 650 } 651 } 652 653 synchronized (mLock) { 654 for (int i = 0; i < numSessionsToRemove; i++) { 655 Session sessionToRemove = mSessions.get(sessionsToRemove.valueAt(i)); 656 657 if (sessionToRemove != null) { 658 if (sessionToRemove.isSavingLocked()) { 659 if (sVerbose) { 660 Slog.v(TAG, "Session " + sessionToRemove.id + " is saving"); 661 } 662 } else { 663 if (sDebug) { 664 Slog.i(TAG, "Prune session " + sessionToRemove.id + " (" 665 + sessionToRemove.getActivityTokenLocked() + ")"); 666 } 667 sessionToRemove.removeSelfLocked(); 668 } 669 } 670 } 671 } 672 673 return null; 674 } 675 } 676} 677