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 21 import static com.android.server.autofill.Helper.sVerbose; 22 23 import android.annotation.NonNull; 24 import android.annotation.Nullable; 25 import android.content.ComponentName; 26 import android.content.Context; 27 import android.content.Intent; 28 import android.content.IntentSender; 29 import android.os.Handler; 30 import android.os.ICancellationSignal; 31 import android.os.RemoteException; 32 import android.service.autofill.AutofillService; 33 import android.service.autofill.FillRequest; 34 import android.service.autofill.FillResponse; 35 import android.service.autofill.IAutoFillService; 36 import android.service.autofill.IFillCallback; 37 import android.service.autofill.ISaveCallback; 38 import android.service.autofill.SaveRequest; 39 import android.text.format.DateUtils; 40 import android.util.Slog; 41 42 import com.android.internal.infra.AbstractRemoteService; 43 import com.android.internal.infra.ServiceConnector; 44 import com.android.internal.os.IResultReceiver; 45 46 import java.util.concurrent.CancellationException; 47 import java.util.concurrent.CompletableFuture; 48 import java.util.concurrent.TimeUnit; 49 import java.util.concurrent.TimeoutException; 50 import java.util.concurrent.atomic.AtomicReference; 51 52 final class RemoteFillService extends ServiceConnector.Impl<IAutoFillService> { 53 54 private static final String TAG = "RemoteFillService"; 55 56 private static final long TIMEOUT_IDLE_BIND_MILLIS = 5 * DateUtils.SECOND_IN_MILLIS; 57 private static final long TIMEOUT_REMOTE_REQUEST_MILLIS = 5 * DateUtils.SECOND_IN_MILLIS; 58 59 private final FillServiceCallbacks mCallbacks; 60 private final Object mLock = new Object(); 61 private CompletableFuture<FillResponse> mPendingFillRequest; 62 private int mPendingFillRequestId = INVALID_REQUEST_ID; 63 private final ComponentName mComponentName; 64 65 public interface FillServiceCallbacks 66 extends AbstractRemoteService.VultureCallback<RemoteFillService> { onFillRequestSuccess(int requestId, @Nullable FillResponse response, @NonNull String servicePackageName, int requestFlags)67 void onFillRequestSuccess(int requestId, @Nullable FillResponse response, 68 @NonNull String servicePackageName, int requestFlags); onFillRequestFailure(int requestId, @Nullable CharSequence message)69 void onFillRequestFailure(int requestId, @Nullable CharSequence message); onFillRequestTimeout(int requestId)70 void onFillRequestTimeout(int requestId); onSaveRequestSuccess(@onNull String servicePackageName, @Nullable IntentSender intentSender)71 void onSaveRequestSuccess(@NonNull String servicePackageName, 72 @Nullable IntentSender intentSender); 73 // TODO(b/80093094): add timeout here too? onSaveRequestFailure(@ullable CharSequence message, @NonNull String servicePackageName)74 void onSaveRequestFailure(@Nullable CharSequence message, 75 @NonNull String servicePackageName); 76 } 77 RemoteFillService(Context context, ComponentName componentName, int userId, FillServiceCallbacks callbacks, boolean bindInstantServiceAllowed)78 RemoteFillService(Context context, ComponentName componentName, int userId, 79 FillServiceCallbacks callbacks, boolean bindInstantServiceAllowed) { 80 super(context, new Intent(AutofillService.SERVICE_INTERFACE).setComponent(componentName), 81 Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS 82 | (bindInstantServiceAllowed ? Context.BIND_ALLOW_INSTANT : 0), 83 userId, IAutoFillService.Stub::asInterface); 84 mCallbacks = callbacks; 85 mComponentName = componentName; 86 } 87 88 @Override // from ServiceConnector.Impl onServiceConnectionStatusChanged(IAutoFillService service, boolean connected)89 protected void onServiceConnectionStatusChanged(IAutoFillService service, boolean connected) { 90 try { 91 service.onConnectedStateChanged(connected); 92 } catch (Exception e) { 93 Slog.w(TAG, "Exception calling onConnectedStateChanged(" + connected + "): " + e); 94 } 95 } 96 dispatchCancellationSignal(@ullable ICancellationSignal signal)97 private void dispatchCancellationSignal(@Nullable ICancellationSignal signal) { 98 if (signal == null) { 99 return; 100 } 101 try { 102 signal.cancel(); 103 } catch (RemoteException e) { 104 Slog.e(TAG, "Error requesting a cancellation", e); 105 } 106 } 107 108 @Override // from ServiceConnector.Impl getAutoDisconnectTimeoutMs()109 protected long getAutoDisconnectTimeoutMs() { 110 return TIMEOUT_IDLE_BIND_MILLIS; 111 } 112 113 @Override // from ServiceConnector.Impl addLast(Job<IAutoFillService, ?> iAutoFillServiceJob)114 public void addLast(Job<IAutoFillService, ?> iAutoFillServiceJob) { 115 // Only maintain single request at a time 116 cancelPendingJobs(); 117 super.addLast(iAutoFillServiceJob); 118 } 119 120 /** 121 * Cancel the currently pending request. 122 * 123 * <p>This can be used when the request is unnecessary or will be superceeded by a request that 124 * will soon be queued. 125 * 126 * @return the id of the canceled request, or {@link FillRequest#INVALID_REQUEST_ID} if no 127 * {@link FillRequest} was canceled. 128 */ cancelCurrentRequest()129 public int cancelCurrentRequest() { 130 synchronized (mLock) { 131 return mPendingFillRequest != null && mPendingFillRequest.cancel(false) 132 ? mPendingFillRequestId 133 : INVALID_REQUEST_ID; 134 } 135 } 136 onFillRequest(@onNull FillRequest request)137 public void onFillRequest(@NonNull FillRequest request) { 138 if (sVerbose) { 139 Slog.v(TAG, "onFillRequest:" + request); 140 } 141 AtomicReference<ICancellationSignal> cancellationSink = new AtomicReference<>(); 142 AtomicReference<CompletableFuture<FillResponse>> futureRef = new AtomicReference<>(); 143 144 CompletableFuture<FillResponse> connectThenFillRequest = postAsync(remoteService -> { 145 if (sVerbose) { 146 Slog.v(TAG, "calling onFillRequest() for id=" + request.getId()); 147 } 148 149 CompletableFuture<FillResponse> fillRequest = new CompletableFuture<>(); 150 remoteService.onFillRequest(request, new IFillCallback.Stub() { 151 @Override 152 public void onCancellable(ICancellationSignal cancellation) { 153 CompletableFuture<FillResponse> future = futureRef.get(); 154 if (future != null && future.isCancelled()) { 155 dispatchCancellationSignal(cancellation); 156 } else { 157 cancellationSink.set(cancellation); 158 } 159 } 160 161 @Override 162 public void onSuccess(FillResponse response) { 163 fillRequest.complete(response); 164 } 165 166 @Override 167 public void onFailure(int requestId, CharSequence message) { 168 String errorMessage = message == null ? "" : String.valueOf(message); 169 fillRequest.completeExceptionally( 170 new RuntimeException(errorMessage)); 171 } 172 }); 173 return fillRequest; 174 }).orTimeout(TIMEOUT_REMOTE_REQUEST_MILLIS, TimeUnit.MILLISECONDS); 175 futureRef.set(connectThenFillRequest); 176 177 synchronized (mLock) { 178 mPendingFillRequest = connectThenFillRequest; 179 mPendingFillRequestId = request.getId(); 180 } 181 182 connectThenFillRequest.whenComplete((res, err) -> Handler.getMain().post(() -> { 183 synchronized (mLock) { 184 mPendingFillRequest = null; 185 mPendingFillRequestId = INVALID_REQUEST_ID; 186 } 187 if (err == null) { 188 mCallbacks.onFillRequestSuccess(request.getId(), res, 189 mComponentName.getPackageName(), request.getFlags()); 190 } else { 191 Slog.e(TAG, "Error calling on fill request", err); 192 if (err instanceof TimeoutException) { 193 dispatchCancellationSignal(cancellationSink.get()); 194 mCallbacks.onFillRequestTimeout(request.getId()); 195 } else if (err instanceof CancellationException) { 196 dispatchCancellationSignal(cancellationSink.get()); 197 } else { 198 mCallbacks.onFillRequestFailure(request.getId(), err.getMessage()); 199 } 200 } 201 })); 202 } 203 onSaveRequest(@onNull SaveRequest request)204 public void onSaveRequest(@NonNull SaveRequest request) { 205 postAsync(service -> { 206 if (sVerbose) Slog.v(TAG, "calling onSaveRequest()"); 207 208 CompletableFuture<IntentSender> save = new CompletableFuture<>(); 209 service.onSaveRequest(request, new ISaveCallback.Stub() { 210 @Override 211 public void onSuccess(IntentSender intentSender) { 212 save.complete(intentSender); 213 } 214 215 @Override 216 public void onFailure(CharSequence message) { 217 save.completeExceptionally(new RuntimeException(String.valueOf(message))); 218 } 219 }); 220 return save; 221 }).orTimeout(TIMEOUT_REMOTE_REQUEST_MILLIS, TimeUnit.MILLISECONDS) 222 .whenComplete((res, err) -> Handler.getMain().post(() -> { 223 if (err == null) { 224 mCallbacks.onSaveRequestSuccess(mComponentName.getPackageName(), res); 225 } else { 226 mCallbacks.onSaveRequestFailure( 227 mComponentName.getPackageName(), err.getMessage()); 228 } 229 })); 230 } 231 onSavedPasswordCountRequest(IResultReceiver receiver)232 void onSavedPasswordCountRequest(IResultReceiver receiver) { 233 run(service -> service.onSavedPasswordCountRequest(receiver)); 234 } 235 destroy()236 public void destroy() { 237 unbind(); 238 } 239 } 240