blob: d42943ce76fecaf4ca617f1604917c7a2300aca4 [file] [log] [blame]
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.autofill;
import static android.service.autofill.augmented.Helper.logResponse;
import static com.android.server.autofill.Helper.sDebug;
import static com.android.server.autofill.Helper.sVerbose;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.app.AppGlobals;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.pm.ServiceInfo;
import android.os.Bundle;
import android.os.IBinder;
import android.os.ICancellationSignal;
import android.os.RemoteException;
import android.os.SystemClock;
import android.service.autofill.augmented.AugmentedAutofillService;
import android.service.autofill.augmented.IAugmentedAutofillService;
import android.service.autofill.augmented.IFillCallback;
import android.util.Pair;
import android.util.Slog;
import android.view.autofill.AutofillId;
import android.view.autofill.AutofillManager;
import android.view.autofill.AutofillValue;
import android.view.autofill.IAutoFillManagerClient;
import com.android.internal.infra.AbstractSinglePendingRequestRemoteService;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.os.IResultReceiver;
final class RemoteAugmentedAutofillService
extends AbstractSinglePendingRequestRemoteService<RemoteAugmentedAutofillService,
IAugmentedAutofillService> {
private static final String TAG = RemoteAugmentedAutofillService.class.getSimpleName();
private final int mIdleUnbindTimeoutMs;
private final int mRequestTimeoutMs;
RemoteAugmentedAutofillService(Context context, ComponentName serviceName,
int userId, RemoteAugmentedAutofillServiceCallbacks callbacks,
boolean bindInstantServiceAllowed, boolean verbose, int idleUnbindTimeoutMs,
int requestTimeoutMs) {
super(context, AugmentedAutofillService.SERVICE_INTERFACE, serviceName, userId, callbacks,
context.getMainThreadHandler(),
bindInstantServiceAllowed ? Context.BIND_ALLOW_INSTANT : 0, verbose);
mIdleUnbindTimeoutMs = idleUnbindTimeoutMs;
mRequestTimeoutMs = requestTimeoutMs;
// Bind right away.
scheduleBind();
}
@Nullable
static Pair<ServiceInfo, ComponentName> getComponentName(@NonNull String componentName,
@UserIdInt int userId, boolean isTemporary) {
int flags = PackageManager.GET_META_DATA;
if (!isTemporary) {
flags |= PackageManager.MATCH_SYSTEM_ONLY;
}
final ComponentName serviceComponent;
ServiceInfo serviceInfo = null;
try {
serviceComponent = ComponentName.unflattenFromString(componentName);
serviceInfo = AppGlobals.getPackageManager().getServiceInfo(serviceComponent, flags,
userId);
if (serviceInfo == null) {
Slog.e(TAG, "Bad service name for flags " + flags + ": " + componentName);
return null;
}
} catch (Exception e) {
Slog.e(TAG, "Error getting service info for '" + componentName + "': " + e);
return null;
}
return new Pair<>(serviceInfo, serviceComponent);
}
@Override // from RemoteService
protected void handleOnConnectedStateChanged(boolean state) {
if (state && getTimeoutIdleBindMillis() != PERMANENT_BOUND_TIMEOUT_MS) {
scheduleUnbind();
}
try {
if (state) {
mService.onConnected(sDebug, sVerbose);
} else {
mService.onDisconnected();
}
} catch (Exception e) {
Slog.w(mTag, "Exception calling onConnectedStateChanged(" + state + "): " + e);
}
}
@Override // from AbstractRemoteService
protected IAugmentedAutofillService getServiceInterface(IBinder service) {
return IAugmentedAutofillService.Stub.asInterface(service);
}
@Override // from AbstractRemoteService
protected long getTimeoutIdleBindMillis() {
return mIdleUnbindTimeoutMs;
}
@Override // from AbstractRemoteService
protected long getRemoteRequestMillis() {
return mRequestTimeoutMs;
}
/**
* Called by {@link Session} to request augmented autofill.
*/
public void onRequestAutofillLocked(int sessionId, @NonNull IAutoFillManagerClient client,
int taskId, @NonNull ComponentName activityComponent, @NonNull AutofillId focusedId,
@Nullable AutofillValue focusedValue) {
scheduleRequest(new PendingAutofillRequest(this, sessionId, client, taskId,
activityComponent, focusedId, focusedValue));
}
@Override
public String toString() {
return "RemoteAugmentedAutofillService["
+ ComponentName.flattenToShortString(getComponentName()) + "]";
}
/**
* Called by {@link Session} when it's time to destroy all augmented autofill requests.
*/
public void onDestroyAutofillWindowsRequest() {
scheduleAsyncRequest((s) -> s.onDestroyAllFillWindowsRequest());
}
private void dispatchOnFillTimeout(@NonNull ICancellationSignal cancellation) {
mHandler.post(() -> {
try {
cancellation.cancel();
} catch (RemoteException e) {
Slog.w(mTag, "Error calling cancellation signal: " + e);
}
});
}
// TODO(b/123100811): inline into PendingAutofillRequest if it doesn't have any other subclass
private abstract static class MyPendingRequest
extends PendingRequest<RemoteAugmentedAutofillService, IAugmentedAutofillService> {
protected final int mSessionId;
private MyPendingRequest(@NonNull RemoteAugmentedAutofillService service, int sessionId) {
super(service);
mSessionId = sessionId;
}
}
private static final class PendingAutofillRequest extends MyPendingRequest {
private final @NonNull AutofillId mFocusedId;
private final @Nullable AutofillValue mFocusedValue;
private final @NonNull IAutoFillManagerClient mClient;
private final @NonNull ComponentName mActivityComponent;
private final int mSessionId;
private final int mTaskId;
private final long mRequestTime = SystemClock.elapsedRealtime();
private final @NonNull IFillCallback mCallback;
private ICancellationSignal mCancellation;
protected PendingAutofillRequest(@NonNull RemoteAugmentedAutofillService service,
int sessionId, @NonNull IAutoFillManagerClient client, int taskId,
@NonNull ComponentName activityComponent, @NonNull AutofillId focusedId,
@Nullable AutofillValue focusedValue) {
super(service, sessionId);
mClient = client;
mSessionId = sessionId;
mTaskId = taskId;
mActivityComponent = activityComponent;
mFocusedId = focusedId;
mFocusedValue = focusedValue;
mCallback = new IFillCallback.Stub() {
@Override
public void onSuccess() {
if (!finish()) return;
// NOTE: so far we don't need notify RemoteAugmentedAutofillServiceCallbacks
}
@Override
public void onCancellable(ICancellationSignal cancellation) {
synchronized (mLock) {
final boolean cancelled;
synchronized (mLock) {
mCancellation = cancellation;
cancelled = isCancelledLocked();
}
if (cancelled) {
try {
cancellation.cancel();
} catch (RemoteException e) {
Slog.e(mTag, "Error requesting a cancellation", e);
}
}
}
}
@Override
public boolean isCompleted() {
return isRequestCompleted();
}
@Override
public void cancel() {
PendingAutofillRequest.this.cancel();
}
};
}
@Override
public void run() {
synchronized (mLock) {
if (isCancelledLocked()) {
if (sDebug) Slog.d(mTag, "run() called after canceled");
return;
}
}
final RemoteAugmentedAutofillService remoteService = getService();
if (remoteService == null) return;
final IResultReceiver receiver = new IResultReceiver.Stub() {
@Override
public void send(int resultCode, Bundle resultData) throws RemoteException {
final IBinder realClient = resultData
.getBinder(AutofillManager.EXTRA_AUGMENTED_AUTOFILL_CLIENT);
remoteService.mService.onFillRequest(mSessionId, realClient, mTaskId,
mActivityComponent, mFocusedId, mFocusedValue, mRequestTime, mCallback);
}
};
// TODO(b/122728762): set cancellation signal, timeout (from both mClient and service),
// cache IAugmentedAutofillManagerClient reference, etc...
try {
mClient.getAugmentedAutofillClient(receiver);
} catch (RemoteException e) {
Slog.e(TAG, "exception handling getAugmentedAutofillClient() for "
+ mSessionId + ": " + e);
finish();
}
}
@Override
protected void onTimeout(RemoteAugmentedAutofillService remoteService) {
// TODO(b/122858578): must update the logged AUTOFILL_AUGMENTED_REQUEST with the
// timeout
Slog.w(TAG, "PendingAutofillRequest timed out (" + remoteService.mRequestTimeoutMs
+ "ms) for " + remoteService);
// NOTE: so far we don't need notify RemoteAugmentedAutofillServiceCallbacks
final ICancellationSignal cancellation;
synchronized (mLock) {
cancellation = mCancellation;
}
if (cancellation != null) {
remoteService.dispatchOnFillTimeout(cancellation);
}
finish();
logResponse(MetricsEvent.TYPE_ERROR, remoteService.getComponentName().getPackageName(),
mActivityComponent, mSessionId, remoteService.mRequestTimeoutMs);
}
@Override
public boolean cancel() {
if (!super.cancel()) return false;
final ICancellationSignal cancellation;
synchronized (mLock) {
cancellation = mCancellation;
}
if (cancellation != null) {
try {
cancellation.cancel();
} catch (RemoteException e) {
Slog.e(mTag, "Error cancelling an augmented fill request", e);
}
}
return true;
}
}
public interface RemoteAugmentedAutofillServiceCallbacks
extends VultureCallback<RemoteAugmentedAutofillService> {
// NOTE: so far we don't need to notify the callback implementation (an inner class on
// AutofillManagerServiceImpl) of the request results (success, timeouts, etc..), so this
// callback interface is empty.
}
}