Merge "Refactored AbstractRemoteService in 2 classes."

This commit is contained in:
Felipe Leme
2018-12-04 06:26:49 +00:00
committed by Android (Google) Code Review
9 changed files with 278 additions and 70 deletions

View File

@@ -60,6 +60,7 @@ public abstract class SmartSuggestionsService extends Service {
// TODO(b/111330312): STOPSHIP use dynamic value, or change to false
static final boolean DEBUG = true;
static final boolean VERBOSE = false;
/**
* The {@link Intent} that must be declared as handled by the service.
@@ -209,7 +210,11 @@ public abstract class SmartSuggestionsService extends Service {
* @param sessionId the session's Id
*/
public void onCreateInteractionSession(@NonNull InteractionContext context,
@NonNull InteractionSessionId sessionId) {}
@NonNull InteractionSessionId sessionId) {
if (VERBOSE) {
Log.v(TAG, "onCreateInteractionSession(id=" + sessionId + ", ctx=" + context + ")");
}
}
/**
* Notifies the service of {@link ContentCaptureEvent events} associated with a content capture
@@ -319,7 +324,11 @@ public abstract class SmartSuggestionsService extends Service {
*
* @param sessionId the id of the session to destroy
*/
public void onDestroyInteractionSession(@NonNull InteractionSessionId sessionId) {}
public void onDestroyInteractionSession(@NonNull InteractionSessionId sessionId) {
if (VERBOSE) {
Log.v(TAG, "onDestroyInteractionSession(id=" + sessionId + ")");
}
}
/** @hide */
static final class AutofillProxy {

View File

@@ -189,7 +189,7 @@ public final class ContentCaptureManager {
}
}
private void handleSessionStarted(int resultCode) {
private void handleSessionStarted(int resultCode) {
mState = resultCode;
mDisabled.set(mState == STATE_DISABLED);
if (VERBOSE) {

View File

@@ -40,9 +40,9 @@ import android.service.autofill.SaveRequest;
import android.text.format.DateUtils;
import android.util.Slog;
import com.android.server.AbstractRemoteService;
import com.android.server.AbstractSinglePendingRequestRemoteService;
final class RemoteFillService extends AbstractRemoteService {
final class RemoteFillService extends AbstractSinglePendingRequestRemoteService<RemoteFillService> {
private static final long TIMEOUT_IDLE_BIND_MILLIS = 5 * DateUtils.SECOND_IN_MILLIS;
private static final long TIMEOUT_REMOTE_REQUEST_MILLIS = 5 * DateUtils.SECOND_IN_MILLIS;
@@ -69,8 +69,8 @@ final class RemoteFillService extends AbstractRemoteService {
mCallbacks = callbacks;
}
@Override
protected void onConnectedStateChanged(boolean state) {
@Override // from AbstractRemoteService
protected void handleOnConnectedStateChanged(boolean state) {
if (mAutoFillService == null) {
Slog.w(mTag, "onConnectedStateChanged(): null service");
return;
@@ -82,18 +82,18 @@ final class RemoteFillService extends AbstractRemoteService {
}
}
@Override
@Override // from AbstractRemoteService
protected IInterface getServiceInterface(IBinder service) {
mAutoFillService = IAutoFillService.Stub.asInterface(service);
return mAutoFillService;
}
@Override
@Override // from AbstractRemoteService
protected long getTimeoutIdleBindMillis() {
return TIMEOUT_IDLE_BIND_MILLIS;
}
@Override
@Override // from AbstractRemoteService
protected long getRemoteRequestMillis() {
return TIMEOUT_REMOTE_REQUEST_MILLIS;
}
@@ -136,6 +136,19 @@ final class RemoteFillService extends AbstractRemoteService {
scheduleRequest(new PendingSaveRequest(request, this));
}
private boolean handleResponseCallbackCommon(
@NonNull PendingRequest<RemoteFillService> pendingRequest) {
if (isDestroyed()) return false;
if (mPendingRequest == pendingRequest) {
mPendingRequest = null;
}
if (mPendingRequest == null) {
scheduleUnbind();
}
return true;
}
private void dispatchOnFillRequestSuccess(@NonNull PendingFillRequest pendingRequest,
@Nullable FillResponse response, int requestFlags) {
mHandler.post(() -> {

View File

@@ -902,7 +902,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
// VultureCallback
@Override
public void onServiceDied(AbstractRemoteService service) {
public void onServiceDied(AbstractRemoteService<? extends AbstractRemoteService<?>> service) {
Slog.w(TAG, "removing session because service died");
forceRemoveSelfLocked();
}

View File

@@ -0,0 +1,96 @@
/*
* 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;
import android.annotation.NonNull;
import android.content.ComponentName;
import android.content.Context;
import android.util.Slog;
import java.io.PrintWriter;
import java.util.ArrayList;
/**
* Base class representing a remote service that can queue multiple pending requests while not
* bound.
*
* @param <S> the concrete remote service class
*
* @hide
*/
public abstract class AbstractMultiplePendingRequestsRemoteService<
S extends AbstractMultiplePendingRequestsRemoteService<S>>
extends AbstractRemoteService<S> {
private final int mInitialCapacity;
protected ArrayList<PendingRequest<S>> mPendingRequests;
public AbstractMultiplePendingRequestsRemoteService(@NonNull Context context,
@NonNull String serviceInterface, @NonNull ComponentName componentName, int userId,
@NonNull VultureCallback callback, boolean bindInstantServiceAllowed, boolean verbose,
int initialCapacity) {
super(context, serviceInterface, componentName, userId, callback, bindInstantServiceAllowed,
verbose);
mInitialCapacity = initialCapacity;
}
@Override // from AbstractRemoteService
void handlePendingRequests() {
if (mPendingRequests != null) {
final int size = mPendingRequests.size();
if (mVerbose) Slog.v(mTag, "Sending " + size + " pending requests");
for (int i = 0; i < size; i++) {
mPendingRequests.get(i).run();
}
mPendingRequests = null;
}
}
@Override // from AbstractRemoteService
protected void handleOnDestroy() {
if (mPendingRequests != null) {
final int size = mPendingRequests.size();
if (mVerbose) Slog.v(mTag, "Canceling " + size + " pending requests");
for (int i = 0; i < size; i++) {
mPendingRequests.get(i).cancel();
}
mPendingRequests = null;
}
}
@Override // from AbstractRemoteService
public void dump(@NonNull String prefix, @NonNull PrintWriter pw) {
super.dump(prefix, pw);
pw.append(prefix).append("initialCapacity=").append(String.valueOf(mInitialCapacity))
.println();
final int size = mPendingRequests == null ? 0 : mPendingRequests.size();
pw.append(prefix).append("pendingRequests=").append(String.valueOf(size)).println();
}
@Override // from AbstractRemoteService
void handlePendingRequestWhileUnBound(@NonNull PendingRequest<S> pendingRequest) {
if (mPendingRequests == null) {
mPendingRequests = new ArrayList<>(mInitialCapacity);
}
mPendingRequests.add(pendingRequest);
if (mVerbose) {
Slog.v(mTag, "queued " + mPendingRequests.size() + " requests; last=" + pendingRequest);
}
}
}

View File

@@ -45,13 +45,20 @@ import java.lang.ref.WeakReference;
*
* <p>All state of this class is modified on a handler thread.
*
* <p><b>NOTE: </b>this class should not be extended directly, you should extend either
* {@link AbstractSinglePendingRequestRemoteService} or
* {@link AbstractMultiplePendingRequestsRemoteService}.
*
* <p>See {@code com.android.server.autofill.RemoteFillService} for a concrete
* (no pun intended) example of how to use it.
*
* @param <S> the concrete remote service class
*
* @hide
*/
//TODO(b/117779333): improve javadoc above instead of using Autofill as an example
public abstract class AbstractRemoteService implements DeathRecipient {
public abstract class AbstractRemoteService<S extends AbstractRemoteService<S>>
implements DeathRecipient {
private static final int MSG_UNBIND = 1;
@@ -64,8 +71,6 @@ public abstract class AbstractRemoteService implements DeathRecipient {
protected final Handler mHandler;
protected final ComponentName mComponentName;
protected PendingRequest<? extends AbstractRemoteService> mPendingRequest;
private final Context mContext;
private final Intent mIntent;
private final VultureCallback mVultureCallback;
@@ -88,10 +93,11 @@ public abstract class AbstractRemoteService implements DeathRecipient {
*
* @param service service that died!
*/
void onServiceDied(AbstractRemoteService service);
void onServiceDied(AbstractRemoteService<? extends AbstractRemoteService<?>> service);
}
public AbstractRemoteService(@NonNull Context context, @NonNull String serviceInterface,
// NOTE: must be package-protected so this class is not extend outside
AbstractRemoteService(@NonNull Context context, @NonNull String serviceInterface,
@NonNull ComponentName componentName, int userId, @NonNull VultureCallback callback,
boolean bindInstantServiceAllowed, boolean verbose) {
mContext = context;
@@ -118,12 +124,25 @@ public abstract class AbstractRemoteService implements DeathRecipient {
return mDestroyed;
}
private void handleOnConnectedStateChangedInternal(boolean connected) {
if (connected) {
handlePendingRequests();
}
handleOnConnectedStateChanged(connected);
}
/**
* Callback called when the system connected / disconnected to the service.
* Handles the pending requests when the connection it bounds to the remote service.
*/
abstract void handlePendingRequests();
/**
* Callback called when the system connected / disconnected to the service and the pending
* requests have been handled.
*
* @param state {@code true} when connected, {@code false} when disconnected.
*/
protected void onConnectedStateChanged(boolean state) {
protected void handleOnConnectedStateChanged(boolean state) {
}
/**
@@ -144,14 +163,18 @@ public abstract class AbstractRemoteService implements DeathRecipient {
private void handleDestroy() {
if (checkIfDestroyed()) return;
if (mPendingRequest != null) {
mPendingRequest.cancel();
mPendingRequest = null;
}
ensureUnbound();
handleOnDestroy();
handleEnsureUnbound();
mDestroyed = true;
}
/**
* Clears the state when this object is destroyed.
*
* <p>Typically used to cancel the pending requests.
*/
protected abstract void handleOnDestroy();
@Override // from DeathRecipient
public void binderDied() {
mHandler.sendMessage(obtainMessage(AbstractRemoteService::handleBinderDied, this));
@@ -183,9 +206,7 @@ public abstract class AbstractRemoteService implements DeathRecipient {
pw.append(prefix).append(tab).append("destroyed=")
.append(String.valueOf(mDestroyed)).println();
pw.append(prefix).append(tab).append("bound=")
.append(String.valueOf(isBound())).println();
pw.append(prefix).append(tab).append("hasPendingRequest=")
.append(String.valueOf(mPendingRequest != null)).println();
.append(String.valueOf(handleIsBound())).println();
pw.append(prefix).append("mBindInstantServiceAllowed=").println(mBindInstantServiceAllowed);
pw.append(prefix).append("idleTimeout=")
.append(Long.toString(getTimeoutIdleBindMillis() / 1000)).append("s").println();
@@ -194,7 +215,7 @@ public abstract class AbstractRemoteService implements DeathRecipient {
pw.println();
}
protected void scheduleRequest(PendingRequest<? extends AbstractRemoteService> pendingRequest) {
protected void scheduleRequest(@NonNull PendingRequest<S> pendingRequest) {
mHandler.sendMessage(obtainMessage(
AbstractRemoteService::handlePendingRequest, this, pendingRequest));
}
@@ -215,19 +236,20 @@ public abstract class AbstractRemoteService implements DeathRecipient {
private void handleUnbind() {
if (checkIfDestroyed()) return;
ensureUnbound();
handleEnsureUnbound();
}
private void handlePendingRequest(
PendingRequest<? extends AbstractRemoteService> pendingRequest) {
/**
* Handles a request, either processing it right now when bound, or saving it to be handled when
* bound.
*/
protected final void handlePendingRequest(@NonNull PendingRequest<S> pendingRequest) {
if (checkIfDestroyed() || mCompleted) return;
if (!isBound()) {
if (mPendingRequest != null) {
mPendingRequest.cancel();
}
mPendingRequest = pendingRequest;
ensureBound();
if (!handleIsBound()) {
if (mVerbose) Slog.v(mTag, "handlePendingRequest(): queuing" + pendingRequest);
handlePendingRequestWhileUnBound(pendingRequest);
handleEnsureBound();
} else {
if (mVerbose) Slog.v(mTag, "handlePendingRequest(): " + pendingRequest);
pendingRequest.run();
@@ -237,12 +259,17 @@ public abstract class AbstractRemoteService implements DeathRecipient {
}
}
private boolean isBound() {
/**
* Defines what to do with a request that arrives while not bound to the service.
*/
abstract void handlePendingRequestWhileUnBound(@NonNull PendingRequest<S> pendingRequest);
private boolean handleIsBound() {
return mServiceInterface != null;
}
private void ensureBound() {
if (isBound() || mBinding) return;
private void handleEnsureBound() {
if (handleIsBound() || mBinding) return;
if (mVerbose) Slog.v(mTag, "ensureBound()");
mBinding = true;
@@ -265,13 +292,13 @@ public abstract class AbstractRemoteService implements DeathRecipient {
}
}
private void ensureUnbound() {
if (!isBound() && !mBinding) return;
private void handleEnsureUnbound() {
if (!handleIsBound() && !mBinding) return;
if (mVerbose) Slog.v(mTag, "ensureUnbound()");
mBinding = false;
if (isBound()) {
onConnectedStateChanged(false);
if (handleIsBound()) {
handleOnConnectedStateChangedInternal(false);
if (mServiceInterface != null) {
mServiceInterface.asBinder().unlinkToDeath(this, 0);
mServiceInterface = null;
@@ -283,6 +310,7 @@ public abstract class AbstractRemoteService implements DeathRecipient {
private class RemoteServiceConnection implements ServiceConnection {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
if (mVerbose) Slog.v(mTag, "onServiceConnected()");
if (mDestroyed || !mBinding) {
// This is abnormal. Unbinding the connection has been requested already.
Slog.wtf(mTag, "onServiceConnected() was dispatched after unbindService.");
@@ -296,15 +324,7 @@ public abstract class AbstractRemoteService implements DeathRecipient {
handleBinderDied();
return;
}
onConnectedStateChanged(true);
if (mPendingRequest != null) {
final PendingRequest<? extends AbstractRemoteService> pendingRequest =
mPendingRequest;
mPendingRequest = null;
handlePendingRequest(pendingRequest);
}
handleOnConnectedStateChangedInternal(true);
mServiceDied = false;
}
@@ -325,25 +345,12 @@ public abstract class AbstractRemoteService implements DeathRecipient {
return mDestroyed;
}
protected boolean handleResponseCallbackCommon(
PendingRequest<? extends AbstractRemoteService> pendingRequest) {
if (isDestroyed()) return false;
if (mPendingRequest == pendingRequest) {
mPendingRequest = null;
}
if (mPendingRequest == null) {
scheduleUnbind();
}
return true;
}
/**
* Base class for the requests serviced by the remote service.
*
* @param <S> the remote service class
*/
public abstract static class PendingRequest<S extends AbstractRemoteService>
public abstract static class PendingRequest<S extends AbstractRemoteService<S>>
implements Runnable {
protected final String mTag = getClass().getSimpleName();
protected final Object mLock = new Object();

View File

@@ -0,0 +1,82 @@
/*
* 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;
import android.annotation.NonNull;
import android.content.ComponentName;
import android.content.Context;
import android.util.Slog;
import java.io.PrintWriter;
/**
* Base class representing a remote service that can have only one pending requests while not bound.
*
* <p>If another request is received while not bound, the previous one will be canceled.
*
* @param <S> the concrete remote service class
*
* @hide
*/
public abstract class AbstractSinglePendingRequestRemoteService<
S extends AbstractSinglePendingRequestRemoteService<S>> extends AbstractRemoteService<S> {
protected PendingRequest<S> mPendingRequest;
public AbstractSinglePendingRequestRemoteService(@NonNull Context context,
@NonNull String serviceInterface, @NonNull ComponentName componentName, int userId,
@NonNull VultureCallback callback, boolean bindInstantServiceAllowed,
boolean verbose) {
super(context, serviceInterface, componentName, userId, callback, bindInstantServiceAllowed,
verbose);
}
@Override // from AbstractRemoteService
void handlePendingRequests() {
if (mPendingRequest != null) {
final PendingRequest<S> pendingRequest = mPendingRequest;
mPendingRequest = null;
handlePendingRequest(pendingRequest);
}
}
@Override // from AbstractRemoteService
protected void handleOnDestroy() {
if (mPendingRequest != null) {
mPendingRequest.cancel();
mPendingRequest = null;
}
}
@Override // from AbstractRemoteService
public void dump(@NonNull String prefix, @NonNull PrintWriter pw) {
super.dump(prefix, pw);
pw.append(prefix).append("hasPendingRequest=")
.append(String.valueOf(mPendingRequest != null)).println();
}
@Override // from AbstractRemoteService
void handlePendingRequestWhileUnBound(@NonNull PendingRequest<S> pendingRequest) {
if (mPendingRequest != null) {
if (mVerbose) {
Slog.v(mTag, "handlePendingRequestWhileUnBound(): cancelling " + mPendingRequest);
}
mPendingRequest.cancel();
}
mPendingRequest = pendingRequest;
}
}

View File

@@ -200,7 +200,7 @@ final class IntelligencePerUserService
return;
}
if (mMaster.verbose) {
Slog.v(TAG, "sendEvents(): id=" + sessionId + "; events =" + events.size());
Slog.v(TAG, "sendEvents(): id=" + sessionId + ", events=" + events.size());
}
session.sendEventsLocked(events);
}

View File

@@ -36,12 +36,13 @@ import android.view.autofill.IAutoFillManagerClient;
import android.view.intelligence.ContentCaptureEvent;
import com.android.internal.os.IResultReceiver;
import com.android.server.AbstractRemoteService;
import com.android.server.AbstractMultiplePendingRequestsRemoteService;
import java.util.List;
//TODO(b/111276913): rename once the final name is defined
final class RemoteIntelligenceService extends AbstractRemoteService {
final class RemoteIntelligenceService
extends AbstractMultiplePendingRequestsRemoteService<RemoteIntelligenceService> {
private static final String TAG = "RemoteIntelligenceService";
@@ -56,7 +57,7 @@ final class RemoteIntelligenceService extends AbstractRemoteService {
RemoteIntelligenceServiceCallbacks callbacks, boolean bindInstantServiceAllowed,
boolean verbose) {
super(context, serviceInterface, componentName, userId, callbacks,
bindInstantServiceAllowed, verbose);
bindInstantServiceAllowed, verbose, /* initialCapacity= */ 2);
mCallbacks = callbacks;
}