1 /* 2 * Copyright (C) 2017 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 17 package com.android.server.autofill; 18 19 import static android.service.autofill.FillRequest.INVALID_REQUEST_ID; 20 import static android.service.autofill.Flags.remoteFillServiceUseWeakReference; 21 22 import static com.android.server.autofill.Helper.sVerbose; 23 24 import android.annotation.NonNull; 25 import android.annotation.Nullable; 26 import android.content.ComponentName; 27 import android.content.Context; 28 import android.content.Intent; 29 import android.content.IntentSender; 30 import android.os.Handler; 31 import android.os.IBinder; 32 import android.os.ICancellationSignal; 33 import android.os.RemoteException; 34 import android.service.autofill.AutofillService; 35 import android.service.autofill.ConvertCredentialRequest; 36 import android.service.autofill.ConvertCredentialResponse; 37 import android.service.autofill.FillRequest; 38 import android.service.autofill.FillResponse; 39 import android.service.autofill.IAutoFillService; 40 import android.service.autofill.IConvertCredentialCallback; 41 import android.service.autofill.IFillCallback; 42 import android.service.autofill.ISaveCallback; 43 import android.service.autofill.SaveRequest; 44 import android.text.format.DateUtils; 45 import android.util.Slog; 46 47 import com.android.internal.infra.AbstractRemoteService; 48 import com.android.internal.infra.ServiceConnector; 49 import com.android.internal.os.IResultReceiver; 50 51 import java.lang.ref.WeakReference; 52 import java.util.concurrent.CancellationException; 53 import java.util.concurrent.CompletableFuture; 54 import java.util.concurrent.TimeUnit; 55 import java.util.concurrent.TimeoutException; 56 import java.util.concurrent.atomic.AtomicReference; 57 58 final class RemoteFillService extends ServiceConnector.Impl<IAutoFillService> { 59 60 private static final String TAG = "RemoteFillService"; 61 62 private static final long TIMEOUT_IDLE_BIND_MILLIS = 5 * DateUtils.SECOND_IN_MILLIS; 63 private static final long TIMEOUT_REMOTE_REQUEST_MILLIS = 5 * DateUtils.SECOND_IN_MILLIS; 64 65 private final FillServiceCallbacks mCallbacks; 66 private final Object mLock = new Object(); 67 private CompletableFuture<FillResponse> mPendingFillRequest; 68 private int mPendingFillRequestId = INVALID_REQUEST_ID; 69 private AtomicReference<IFillCallback> mFillCallback; 70 private AtomicReference<ISaveCallback> mSaveCallback; 71 private AtomicReference<IConvertCredentialCallback> mConvertCredentialCallback; 72 private final ComponentName mComponentName; 73 74 private final boolean mIsCredentialAutofillService; 75 isCredentialAutofillService()76 public boolean isCredentialAutofillService() { 77 return mIsCredentialAutofillService; 78 } 79 80 public interface FillServiceCallbacks 81 extends AbstractRemoteService.VultureCallback<RemoteFillService> { onFillRequestSuccess(int requestId, @Nullable FillResponse response, @NonNull String servicePackageName, int requestFlags)82 void onFillRequestSuccess(int requestId, @Nullable FillResponse response, 83 @NonNull String servicePackageName, int requestFlags); 84 onFillRequestFailure(int requestId, Throwable t)85 void onFillRequestFailure(int requestId, Throwable t); 86 onSaveRequestSuccess(@onNull String servicePackageName, @Nullable IntentSender intentSender)87 void onSaveRequestSuccess(@NonNull String servicePackageName, 88 @Nullable IntentSender intentSender); 89 90 // TODO(b/80093094): add timeout here too? onSaveRequestFailure(@ullable CharSequence message, @NonNull String servicePackageName)91 void onSaveRequestFailure(@Nullable CharSequence message, 92 @NonNull String servicePackageName); 93 onConvertCredentialRequestSuccess(@onNull ConvertCredentialResponse convertCredentialResponse)94 void onConvertCredentialRequestSuccess(@NonNull ConvertCredentialResponse 95 convertCredentialResponse); 96 } 97 RemoteFillService(Context context, ComponentName componentName, int userId, FillServiceCallbacks callbacks, boolean bindInstantServiceAllowed, @Nullable ComponentName credentialAutofillService)98 RemoteFillService(Context context, ComponentName componentName, int userId, 99 FillServiceCallbacks callbacks, boolean bindInstantServiceAllowed, 100 @Nullable ComponentName credentialAutofillService) { 101 super(context, new Intent(AutofillService.SERVICE_INTERFACE).setComponent(componentName), 102 Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS 103 | (bindInstantServiceAllowed ? Context.BIND_ALLOW_INSTANT : 0), 104 userId, IAutoFillService.Stub::asInterface); 105 mCallbacks = callbacks; 106 mComponentName = componentName; 107 mIsCredentialAutofillService = mComponentName.equals(credentialAutofillService); 108 } 109 110 @Override // from ServiceConnector.Impl onServiceConnectionStatusChanged(IAutoFillService service, boolean connected)111 protected void onServiceConnectionStatusChanged(IAutoFillService service, boolean connected) { 112 try { 113 service.onConnectedStateChanged(connected); 114 } catch (Exception e) { 115 Slog.w(TAG, "Exception calling onConnectedStateChanged(" + connected + "): " + e); 116 } 117 } 118 dispatchCancellationSignal(@ullable ICancellationSignal signal)119 private void dispatchCancellationSignal(@Nullable ICancellationSignal signal) { 120 if (signal == null) { 121 return; 122 } 123 try { 124 signal.cancel(); 125 } catch (RemoteException e) { 126 Slog.e(TAG, "Error requesting a cancellation", e); 127 } 128 } 129 130 @Override // from ServiceConnector.Impl getAutoDisconnectTimeoutMs()131 protected long getAutoDisconnectTimeoutMs() { 132 return TIMEOUT_IDLE_BIND_MILLIS; 133 } 134 135 @Override // from ServiceConnector.Impl addLast(Job<IAutoFillService, ?> iAutoFillServiceJob)136 public void addLast(Job<IAutoFillService, ?> iAutoFillServiceJob) { 137 // Only maintain single request at a time 138 cancelPendingJobs(); 139 super.addLast(iAutoFillServiceJob); 140 } 141 getComponentName()142 public ComponentName getComponentName() { 143 return mComponentName; 144 } 145 146 /** 147 * Cancel the currently pending request. 148 * 149 * <p>This can be used when the request is unnecessary or will be superceeded by a request that 150 * will soon be queued. 151 * 152 * @return the id of the canceled request, or {@link FillRequest#INVALID_REQUEST_ID} if no 153 * {@link FillRequest} was canceled. 154 */ cancelCurrentRequest()155 public int cancelCurrentRequest() { 156 synchronized (mLock) { 157 return mPendingFillRequest != null && mPendingFillRequest.cancel(false) 158 ? mPendingFillRequestId 159 : INVALID_REQUEST_ID; 160 } 161 } 162 163 static class IFillCallbackDelegate extends IFillCallback.Stub { 164 private WeakReference<IFillCallback> mCallbackWeakRef; 165 IFillCallbackDelegate(IFillCallback callback)166 IFillCallbackDelegate(IFillCallback callback) { 167 mCallbackWeakRef = new WeakReference(callback); 168 } 169 170 @Override onCancellable(ICancellationSignal cancellation)171 public void onCancellable(ICancellationSignal cancellation) throws RemoteException { 172 IFillCallback callback = mCallbackWeakRef.get(); 173 if (callback != null) { 174 callback.onCancellable(cancellation); 175 } 176 } 177 178 @Override onSuccess(FillResponse response)179 public void onSuccess(FillResponse response) throws RemoteException { 180 IFillCallback callback = mCallbackWeakRef.get(); 181 if (callback != null) { 182 callback.onSuccess(response); 183 } 184 } 185 186 @Override onFailure(int requestId, CharSequence message)187 public void onFailure(int requestId, CharSequence message) throws RemoteException { 188 IFillCallback callback = mCallbackWeakRef.get(); 189 if (callback != null) { 190 callback.onFailure(requestId, message); 191 } 192 } 193 } 194 195 static class ISaveCallbackDelegate extends ISaveCallback.Stub { 196 197 private WeakReference<ISaveCallback> mCallbackWeakRef; 198 ISaveCallbackDelegate(ISaveCallback callback)199 ISaveCallbackDelegate(ISaveCallback callback) { 200 mCallbackWeakRef = new WeakReference(callback); 201 } 202 203 @Override onSuccess(IntentSender intentSender)204 public void onSuccess(IntentSender intentSender) throws RemoteException { 205 ISaveCallback callback = mCallbackWeakRef.get(); 206 if (callback != null) { 207 callback.onSuccess(intentSender); 208 } 209 } 210 211 @Override onFailure(CharSequence message)212 public void onFailure(CharSequence message) throws RemoteException { 213 ISaveCallback callback = mCallbackWeakRef.get(); 214 if (callback != null) { 215 callback.onFailure(message); 216 } 217 } 218 } 219 220 static class IConvertCredentialCallbackDelegate extends IConvertCredentialCallback.Stub { 221 222 private WeakReference<IConvertCredentialCallback> mCallbackWeakRef; 223 IConvertCredentialCallbackDelegate(IConvertCredentialCallback callback)224 IConvertCredentialCallbackDelegate(IConvertCredentialCallback callback) { 225 mCallbackWeakRef = new WeakReference(callback); 226 } 227 228 @Override onSuccess(ConvertCredentialResponse convertCredentialResponse)229 public void onSuccess(ConvertCredentialResponse convertCredentialResponse) 230 throws RemoteException { 231 IConvertCredentialCallback callback = mCallbackWeakRef.get(); 232 if (callback != null) { 233 callback.onSuccess(convertCredentialResponse); 234 } 235 } 236 237 @Override onFailure(CharSequence message)238 public void onFailure(CharSequence message) throws RemoteException { 239 IConvertCredentialCallback callback = mCallbackWeakRef.get(); 240 if (callback != null) { 241 callback.onFailure(message); 242 } 243 } 244 } 245 246 /** 247 * Wraps an {@link IFillCallback} object using weak reference. 248 * 249 * This prevents lingering allocation issue by breaking the chain of strong references from 250 * Binder to {@link callback}. Since {@link callback} is not held by Binder anymore, it needs 251 * to be held by {@link mFillCallback} so it's not deallocated prematurely. 252 */ maybeWrapWithWeakReference(IFillCallback callback)253 private IFillCallback maybeWrapWithWeakReference(IFillCallback callback) { 254 if (remoteFillServiceUseWeakReference()) { 255 mFillCallback = new AtomicReference<>(callback); 256 return new IFillCallbackDelegate(callback); 257 } 258 return callback; 259 } 260 261 /** 262 * Wraps an {@link ISaveCallback} object using weak reference. 263 */ maybeWrapWithWeakReference(ISaveCallback callback)264 private ISaveCallback maybeWrapWithWeakReference(ISaveCallback callback) { 265 if (remoteFillServiceUseWeakReference()) { 266 mSaveCallback = new AtomicReference<>(callback); 267 return new ISaveCallbackDelegate(callback); 268 } 269 return callback; 270 } 271 272 /** 273 * Wraps an {@link IConvertCredentialCallback} object using weak reference 274 */ maybeWrapWithWeakReference( IConvertCredentialCallback callback)275 private IConvertCredentialCallback maybeWrapWithWeakReference( 276 IConvertCredentialCallback callback) { 277 if (remoteFillServiceUseWeakReference()) { 278 mConvertCredentialCallback = new AtomicReference<>(callback); 279 return new IConvertCredentialCallbackDelegate(callback); 280 } 281 return callback; 282 } 283 onFillCredentialRequest(@onNull FillRequest request, IBinder autofillCallback)284 public void onFillCredentialRequest(@NonNull FillRequest request, IBinder autofillCallback) { 285 if (sVerbose) { 286 Slog.v(TAG, "onFillRequest:" + request); 287 } 288 AtomicReference<ICancellationSignal> cancellationSink = new AtomicReference<>(); 289 AtomicReference<CompletableFuture<FillResponse>> futureRef = new AtomicReference<>(); 290 291 CompletableFuture<FillResponse> connectThenFillRequest = postAsync(remoteService -> { 292 if (sVerbose) { 293 Slog.v(TAG, "calling onFillRequest() for id=" + request.getId()); 294 } 295 296 CompletableFuture<FillResponse> fillRequest = new CompletableFuture<>(); 297 remoteService.onFillCredentialRequest( 298 request, maybeWrapWithWeakReference(new IFillCallback.Stub() { 299 @Override 300 public void onCancellable(ICancellationSignal cancellation) { 301 CompletableFuture<FillResponse> future = futureRef.get(); 302 if (future != null && future.isCancelled()) { 303 dispatchCancellationSignal(cancellation); 304 } else { 305 cancellationSink.set(cancellation); 306 } 307 } 308 309 @Override 310 public void onSuccess(FillResponse response) { 311 fillRequest.complete(response); 312 } 313 314 @Override 315 public void onFailure(int requestId, CharSequence message) { 316 String errorMessage = message == null ? "" : String.valueOf(message); 317 fillRequest.completeExceptionally( 318 new RuntimeException(errorMessage)); 319 } 320 }), autofillCallback); 321 return fillRequest; 322 }).orTimeout(TIMEOUT_REMOTE_REQUEST_MILLIS, TimeUnit.MILLISECONDS); 323 futureRef.set(connectThenFillRequest); 324 325 synchronized (mLock) { 326 mPendingFillRequest = connectThenFillRequest; 327 mPendingFillRequestId = request.getId(); 328 } 329 330 connectThenFillRequest.whenComplete((res, err) -> Handler.getMain().post(() -> { 331 synchronized (mLock) { 332 mPendingFillRequest = null; 333 mPendingFillRequestId = INVALID_REQUEST_ID; 334 } 335 if (mCallbacks == null) { 336 Slog.w(TAG, "Error calling RemoteFillService - service already unbound"); 337 return; 338 } 339 if (err == null) { 340 mCallbacks.onFillRequestSuccess(request.getId(), res, 341 mComponentName.getPackageName(), request.getFlags()); 342 } else { 343 Slog.e(TAG, "Error calling on fill request", err); 344 if (err instanceof TimeoutException) { 345 dispatchCancellationSignal(cancellationSink.get()); 346 mCallbacks.onFillRequestFailure(request.getId(), err); 347 } else if (err instanceof CancellationException) { 348 // Cancellation is a part of the user flow - don't mark as failure 349 dispatchCancellationSignal(cancellationSink.get()); 350 } else { 351 mCallbacks.onFillRequestFailure(request.getId(), err); 352 } 353 } 354 })); 355 } 356 onFillRequest(@onNull FillRequest request)357 public void onFillRequest(@NonNull FillRequest request) { 358 if (sVerbose) { 359 Slog.v(TAG, "onFillRequest:" + request); 360 } 361 AtomicReference<ICancellationSignal> cancellationSink = new AtomicReference<>(); 362 AtomicReference<CompletableFuture<FillResponse>> futureRef = new AtomicReference<>(); 363 364 CompletableFuture<FillResponse> connectThenFillRequest = postAsync(remoteService -> { 365 if (sVerbose) { 366 Slog.v(TAG, "calling onFillRequest() for id=" + request.getId()); 367 } 368 369 CompletableFuture<FillResponse> fillRequest = new CompletableFuture<>(); 370 remoteService.onFillRequest( 371 request, maybeWrapWithWeakReference(new IFillCallback.Stub() { 372 @Override 373 public void onCancellable(ICancellationSignal cancellation) { 374 CompletableFuture<FillResponse> future = futureRef.get(); 375 if (future != null && future.isCancelled()) { 376 dispatchCancellationSignal(cancellation); 377 } else { 378 cancellationSink.set(cancellation); 379 } 380 } 381 382 @Override 383 public void onSuccess(FillResponse response) { 384 fillRequest.complete(response); 385 } 386 387 @Override 388 public void onFailure(int requestId, CharSequence message) { 389 String errorMessage = message == null ? "" : String.valueOf(message); 390 fillRequest.completeExceptionally( 391 new RuntimeException(errorMessage)); 392 } 393 })); 394 return fillRequest; 395 }).orTimeout(TIMEOUT_REMOTE_REQUEST_MILLIS, TimeUnit.MILLISECONDS); 396 futureRef.set(connectThenFillRequest); 397 398 synchronized (mLock) { 399 mPendingFillRequest = connectThenFillRequest; 400 mPendingFillRequestId = request.getId(); 401 } 402 403 connectThenFillRequest.whenComplete((res, err) -> Handler.getMain().post(() -> { 404 synchronized (mLock) { 405 mPendingFillRequest = null; 406 mPendingFillRequestId = INVALID_REQUEST_ID; 407 } 408 if (err == null) { 409 mCallbacks.onFillRequestSuccess(request.getId(), res, 410 mComponentName.getPackageName(), request.getFlags()); 411 } else { 412 Slog.e(TAG, "Error calling on fill request", err); 413 if (err instanceof TimeoutException) { 414 dispatchCancellationSignal(cancellationSink.get()); 415 mCallbacks.onFillRequestFailure(request.getId(), err); 416 } else if (err instanceof CancellationException) { 417 // Cancellation is a part of the user flow - don't mark as failure 418 dispatchCancellationSignal(cancellationSink.get()); 419 } else { 420 mCallbacks.onFillRequestFailure(request.getId(), err); 421 } 422 } 423 })); 424 } 425 onConvertCredentialRequest( @onNull ConvertCredentialRequest convertCredentialRequest)426 public void onConvertCredentialRequest( 427 @NonNull ConvertCredentialRequest convertCredentialRequest) { 428 if (sVerbose) Slog.v(TAG, "calling onConvertCredentialRequest()"); 429 CompletableFuture<ConvertCredentialResponse> 430 connectThenConvertCredentialRequest = postAsync( 431 remoteService -> { 432 if (sVerbose) { 433 Slog.v(TAG, "calling onConvertCredentialRequest()"); 434 } 435 CompletableFuture<ConvertCredentialResponse> 436 convertCredentialCompletableFuture = new CompletableFuture<>(); 437 remoteService.onConvertCredentialRequest(convertCredentialRequest, 438 maybeWrapWithWeakReference( 439 new IConvertCredentialCallback.Stub() { 440 @Override 441 public void onSuccess(ConvertCredentialResponse 442 convertCredentialResponse) { 443 convertCredentialCompletableFuture 444 .complete(convertCredentialResponse); 445 } 446 447 @Override 448 public void onFailure(CharSequence message) { 449 String errorMessage = 450 message == null ? "" : 451 String.valueOf(message); 452 convertCredentialCompletableFuture 453 .completeExceptionally( 454 new RuntimeException(errorMessage)); 455 } 456 }) 457 ); 458 return convertCredentialCompletableFuture; 459 }).orTimeout(TIMEOUT_REMOTE_REQUEST_MILLIS, TimeUnit.MILLISECONDS); 460 461 connectThenConvertCredentialRequest.whenComplete( 462 (res, err) -> Handler.getMain().post(() -> { 463 if (err == null) { 464 mCallbacks.onConvertCredentialRequestSuccess(res); 465 } else { 466 // TODO: Add a callback function to log this failure 467 Slog.e(TAG, "Error calling on convert credential request", err); 468 } 469 })); 470 } 471 onSaveRequest(@onNull SaveRequest request)472 public void onSaveRequest(@NonNull SaveRequest request) { 473 postAsync(service -> { 474 if (sVerbose) Slog.v(TAG, "calling onSaveRequest()"); 475 476 CompletableFuture<IntentSender> save = new CompletableFuture<>(); 477 service.onSaveRequest(request, maybeWrapWithWeakReference(new ISaveCallback.Stub() { 478 @Override 479 public void onSuccess(IntentSender intentSender) { 480 save.complete(intentSender); 481 } 482 483 @Override 484 public void onFailure(CharSequence message) { 485 save.completeExceptionally(new RuntimeException(String.valueOf(message))); 486 } 487 })); 488 return save; 489 }).orTimeout(TIMEOUT_REMOTE_REQUEST_MILLIS, TimeUnit.MILLISECONDS) 490 .whenComplete((res, err) -> Handler.getMain().post(() -> { 491 if (err == null) { 492 mCallbacks.onSaveRequestSuccess(mComponentName.getPackageName(), res); 493 } else { 494 mCallbacks.onSaveRequestFailure( 495 mComponentName.getPackageName(), err.getMessage()); 496 } 497 })); 498 } 499 onSavedPasswordCountRequest(IResultReceiver receiver)500 void onSavedPasswordCountRequest(IResultReceiver receiver) { 501 run(service -> service.onSavedPasswordCountRequest(receiver)); 502 } 503 destroy()504 public void destroy() { 505 unbind(); 506 } 507 } 508