summaryrefslogtreecommitdiff
path: root/services/appfunctions/java
diff options
context:
space:
mode:
author Tony Mak <tonymak@google.com> 2024-09-28 18:10:52 +0100
committer Desh <oadesina@google.com> 2024-09-30 19:53:58 +0000
commita620ff83578512539a25b6351d034290850acc7a (patch)
tree86c72919b3ddf463121c7744a10fac13f5351c82 /services/appfunctions/java
parent456b5e0388a1d32cad82af0557be7d93792f94ed (diff)
Add a timeout for CancellationSignal issued to AppFunctionService before which it is unbound.
Change-Id: If9c66bf7951b72e66d7780a58595b58c4f495f3d Flag: android.app.appfunctions.flags.enable_app_function_manager Test: atest CtsAppFunctionTestCases -c Bug: 360864791
Diffstat (limited to 'services/appfunctions/java')
-rw-r--r--services/appfunctions/java/com/android/server/appfunctions/AppFunctionManagerServiceImpl.java10
-rw-r--r--services/appfunctions/java/com/android/server/appfunctions/RemoteServiceCaller.java25
-rw-r--r--services/appfunctions/java/com/android/server/appfunctions/RemoteServiceCallerImpl.java29
-rw-r--r--services/appfunctions/java/com/android/server/appfunctions/ServiceConfig.java7
-rw-r--r--services/appfunctions/java/com/android/server/appfunctions/ServiceConfigImpl.java13
5 files changed, 67 insertions, 17 deletions
diff --git a/services/appfunctions/java/com/android/server/appfunctions/AppFunctionManagerServiceImpl.java b/services/appfunctions/java/com/android/server/appfunctions/AppFunctionManagerServiceImpl.java
index b6c8fc7b80c7..14298f416d87 100644
--- a/services/appfunctions/java/com/android/server/appfunctions/AppFunctionManagerServiceImpl.java
+++ b/services/appfunctions/java/com/android/server/appfunctions/AppFunctionManagerServiceImpl.java
@@ -430,6 +430,8 @@ public class AppFunctionManagerServiceImpl extends IAppFunctionManager.Stub {
serviceIntent,
bindFlags,
targetUser,
+ mServiceConfig.getExecuteAppFunctionCancellationTimeoutMillis(),
+ cancellationSignal,
new RunServiceCallCallback<IAppFunctionService>() {
@Override
public void onServiceConnected(
@@ -470,6 +472,14 @@ public class AppFunctionManagerServiceImpl extends IAppFunctionManager.Stub {
"Failed to connect to AppFunctionService",
/* extras= */ null));
}
+
+ @Override
+ public void onCancelled() {
+ // Do not forward the result back to the caller once it has been
+ // canceled. The caller does not need a notification and should
+ // proceed after initiating a cancellation.
+ safeExecuteAppFunctionCallback.disable();
+ }
});
if (!bindServiceResult) {
diff --git a/services/appfunctions/java/com/android/server/appfunctions/RemoteServiceCaller.java b/services/appfunctions/java/com/android/server/appfunctions/RemoteServiceCaller.java
index cd5c3831bc0d..55173c350e71 100644
--- a/services/appfunctions/java/com/android/server/appfunctions/RemoteServiceCaller.java
+++ b/services/appfunctions/java/com/android/server/appfunctions/RemoteServiceCaller.java
@@ -17,12 +17,13 @@ package com.android.server.appfunctions;
import android.annotation.NonNull;
import android.content.Intent;
+import android.os.CancellationSignal;
import android.os.UserHandle;
/**
- * Defines a contract for establishing temporary connections to services and executing operations
- * within a specified timeout. Implementations of this interface provide mechanisms to ensure that
- * services are properly unbound after the operation completes or a timeout occurs.
+ * Defines a contract for establishing temporary connections to services and executing operations.
+ * Implementations of this interface provide mechanisms to ensure that services are properly unbound
+ * after the operation completes or a cancellation timeout occurs.
*
* @param <T> Class of wrapped service.
*/
@@ -30,20 +31,25 @@ public interface RemoteServiceCaller<T> {
/**
* Initiates service binding and executes a provided method when the service connects. Unbinds
- * the service after execution or upon timeout. Returns the result of the bindService API.
+ * the service after execution or upon cancellation timeout. Returns the result of the
+ * bindService API.
*
* <p>When the service connection was made successfully, it's the caller responsibility to
* report the usage is completed and can be unbound by calling {@link
* ServiceUsageCompleteListener#onCompleted()}.
*
- * <p>This method includes a timeout mechanism to prevent the system from being stuck in a state
- * where a service is bound indefinitely (for example, if the binder method never returns). This
- * helps ensure that the calling app does not remain alive unnecessarily.
+ * <p>This method includes a timeout mechanism for cancellation to prevent the system from being
+ * stuck in a state where a service is bound indefinitely. If the app to be bound does not
+ * return the result within `cancellationTimeoutMillis` after the cancellation signal is sent,
+ * this method will unbind the service connection.
*
* @param intent An Intent object that describes the service that should be bound.
* @param bindFlags Flags used to control the binding process See {@link
* android.content.Context#bindService}.
* @param userHandle The UserHandle of the user for which the service should be bound.
+ * @param cancellationTimeoutMillis The timeout before the service is unbound after a
+ * cancellation signal is issued.
+ * @param cancellationSignal The cancellation signal forwarded to the service.
* @param callback A callback to be invoked for various events. See {@link
* RunServiceCallCallback}.
*/
@@ -51,6 +57,8 @@ public interface RemoteServiceCaller<T> {
@NonNull Intent intent,
int bindFlags,
@NonNull UserHandle userHandle,
+ long cancellationTimeoutMillis,
+ @NonNull CancellationSignal cancellationSignal,
@NonNull RunServiceCallCallback<T> callback);
/** An interface for clients to signal that they have finished using a bound service. */
@@ -73,5 +81,8 @@ public interface RemoteServiceCaller<T> {
/** Called when the service connection was failed to establish. */
void onFailedToConnect();
+
+ /** Called when the caller has cancelled this remote service call. */
+ void onCancelled();
}
}
diff --git a/services/appfunctions/java/com/android/server/appfunctions/RemoteServiceCallerImpl.java b/services/appfunctions/java/com/android/server/appfunctions/RemoteServiceCallerImpl.java
index ffca8491abcd..7e3a29afc01c 100644
--- a/services/appfunctions/java/com/android/server/appfunctions/RemoteServiceCallerImpl.java
+++ b/services/appfunctions/java/com/android/server/appfunctions/RemoteServiceCallerImpl.java
@@ -20,6 +20,7 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
+import android.os.CancellationSignal;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
@@ -63,9 +64,17 @@ public class RemoteServiceCallerImpl<T> implements RemoteServiceCaller<T> {
@NonNull Intent intent,
int bindFlags,
@NonNull UserHandle userHandle,
+ long cancellationTimeoutMillis,
+ @NonNull CancellationSignal cancellationSignal,
@NonNull RunServiceCallCallback<T> callback) {
OneOffServiceConnection serviceConnection =
- new OneOffServiceConnection(intent, bindFlags, userHandle, callback);
+ new OneOffServiceConnection(
+ intent,
+ bindFlags,
+ userHandle,
+ cancellationTimeoutMillis,
+ cancellationSignal,
+ callback);
return serviceConnection.bindAndRun();
}
@@ -76,23 +85,38 @@ public class RemoteServiceCallerImpl<T> implements RemoteServiceCaller<T> {
private final int mFlags;
private final UserHandle mUserHandle;
private final RunServiceCallCallback<T> mCallback;
+ private final long mCancellationTimeoutMillis;
+ private final CancellationSignal mCancellationSignal;
+ private final Runnable mCancellationTimeoutRunnable;
OneOffServiceConnection(
@NonNull Intent intent,
int flags,
@NonNull UserHandle userHandle,
+ long cancellationTimeoutMillis,
+ @NonNull CancellationSignal cancellationSignal,
@NonNull RunServiceCallCallback<T> callback) {
mIntent = intent;
mFlags = flags;
mCallback = callback;
mUserHandle = userHandle;
+ mCancellationTimeoutMillis = cancellationTimeoutMillis;
+ mCancellationSignal = cancellationSignal;
+ mCancellationTimeoutRunnable = this::safeUnbind;
}
public boolean bindAndRun() {
boolean bindServiceResult =
mContext.bindServiceAsUser(mIntent, this, mFlags, mUserHandle);
- if (!bindServiceResult) {
+ if (bindServiceResult) {
+ mCancellationSignal.setOnCancelListener(
+ () -> {
+ mCallback.onCancelled();
+ mHandler.postDelayed(
+ mCancellationTimeoutRunnable, mCancellationTimeoutMillis);
+ });
+ } else {
safeUnbind();
}
@@ -126,6 +150,7 @@ public class RemoteServiceCallerImpl<T> implements RemoteServiceCaller<T> {
private void safeUnbind() {
try {
+ mHandler.removeCallbacks(mCancellationTimeoutRunnable);
mContext.unbindService(this);
} catch (Exception ex) {
Log.w(TAG, "Failed to unbind", ex);
diff --git a/services/appfunctions/java/com/android/server/appfunctions/ServiceConfig.java b/services/appfunctions/java/com/android/server/appfunctions/ServiceConfig.java
index caa4bf0e9d27..8d2d1b2dfd00 100644
--- a/services/appfunctions/java/com/android/server/appfunctions/ServiceConfig.java
+++ b/services/appfunctions/java/com/android/server/appfunctions/ServiceConfig.java
@@ -21,6 +21,9 @@ public interface ServiceConfig {
// TODO(b/357551503): Obtain namespace from DeviceConfig.
String NAMESPACE_APP_FUNCTIONS = "appfunctions";
- /** Returns the maximum time to wait for an app function execution to be complete. */
- long getExecuteAppFunctionTimeoutMillis();
+ /**
+ * Returns the timeout for which the system server waits for the app function service to
+ * successfully cancel the execution of an app function before forcefully unbinding the service.
+ */
+ long getExecuteAppFunctionCancellationTimeoutMillis();
}
diff --git a/services/appfunctions/java/com/android/server/appfunctions/ServiceConfigImpl.java b/services/appfunctions/java/com/android/server/appfunctions/ServiceConfigImpl.java
index f18789be5ce8..787f52afda4b 100644
--- a/services/appfunctions/java/com/android/server/appfunctions/ServiceConfigImpl.java
+++ b/services/appfunctions/java/com/android/server/appfunctions/ServiceConfigImpl.java
@@ -20,15 +20,16 @@ import android.provider.DeviceConfig;
/** Implementation of {@link ServiceConfig} */
public class ServiceConfigImpl implements ServiceConfig {
- static final String DEVICE_CONFIG_PROPERTY_EXECUTION_TIMEOUT =
- "execute_app_function_timeout_millis";
- static final long DEFAULT_EXECUTE_APP_FUNCTION_TIMEOUT_MS = 5000L;
+ static final String DEVICE_CONFIG_PROPERTY_EXECUTION_CANCELLATION_TIMEOUT =
+ "execute_app_function_cancellation_timeout_millis";
+ static final long DEFAULT_EXECUTE_APP_FUNCTION_CANCELLATION_TIMEOUT_MS = 5000L;
+
@Override
- public long getExecuteAppFunctionTimeoutMillis() {
+ public long getExecuteAppFunctionCancellationTimeoutMillis() {
return DeviceConfig.getLong(
NAMESPACE_APP_FUNCTIONS,
- DEVICE_CONFIG_PROPERTY_EXECUTION_TIMEOUT,
- DEFAULT_EXECUTE_APP_FUNCTION_TIMEOUT_MS);
+ DEVICE_CONFIG_PROPERTY_EXECUTION_CANCELLATION_TIMEOUT,
+ DEFAULT_EXECUTE_APP_FUNCTION_CANCELLATION_TIMEOUT_MS);
}
}