Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit fce8dfc1 authored by Harshit Mahajan's avatar Harshit Mahajan
Browse files

Marking testAPI to SystemAPI

Since we can not expose @TestApi from module, we need to have SystemApi.
Updating the api to have an executor and Consumer<Bundle> as parameters.
Update notifyHealthCheckPassed to use executor and Consumer<Bundle>.
Also exposing EXTRA_HEALTH_CHECK_PASSED_PACKAGE to make clients aware of
the contents in bundle as part of callback.

Bug: 361126781
Test: atest CtsPackageWatchdogTestCases
Flag: android.crashrecovery.flags.enable_crashrecovery
Change-Id: I3a149b3873d0c9fc3094edbfd5eb2278f61b44da
parent c1ca8871
Loading
Loading
Loading
Loading
+5 −1
Original line number Diff line number Diff line
@@ -14,7 +14,11 @@ java_sdk_library {
    name: "framework-platformcrashrecovery",
    srcs: [":framework-crashrecovery-sources"],
    defaults: ["framework-non-updatable-unbundled-defaults"],
    permitted_packages: ["android.service.watchdog"],
    permitted_packages: [
        "android.service.watchdog",
        "android.crashrecovery",
    ],
    static_libs: ["android.crashrecovery.flags-aconfig-java"],
    aidl: {
        include_dirs: [
            "frameworks/base/core/java",
+2 −0
Original line number Diff line number Diff line
@@ -9,7 +9,9 @@ package android.service.watchdog {
    method @NonNull public abstract java.util.List<java.lang.String> onGetRequestedPackages();
    method @NonNull public abstract java.util.List<android.service.watchdog.ExplicitHealthCheckService.PackageConfig> onGetSupportedPackages();
    method public abstract void onRequestHealthCheck(@NonNull String);
    method @FlaggedApi("android.crashrecovery.flags.enable_crashrecovery") public final void setHealthCheckResultCallback(@Nullable java.util.concurrent.Executor, @Nullable java.util.function.Consumer<android.os.Bundle>);
    field public static final String BIND_PERMISSION = "android.permission.BIND_EXPLICIT_HEALTH_CHECK_SERVICE";
    field @FlaggedApi("android.crashrecovery.flags.enable_crashrecovery") public static final String EXTRA_HEALTH_CHECK_PASSED_PACKAGE = "android.service.watchdog.extra.HEALTH_CHECK_PASSED_PACKAGE";
    field public static final String SERVICE_INTERFACE = "android.service.watchdog.ExplicitHealthCheckService";
  }

+0 −8
Original line number Diff line number Diff line
// Signature format: 2.0
package android.service.watchdog {

  public abstract class ExplicitHealthCheckService extends android.app.Service {
    method public void setCallback(@Nullable android.os.RemoteCallback);
  }

}
+45 −24
Original line number Diff line number Diff line
@@ -18,15 +18,17 @@ package android.service.watchdog;

import static android.os.Parcelable.Creator;

import android.annotation.CallbackExecutor;
import android.annotation.FlaggedApi;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SdkConstant;
import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.app.Service;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.crashrecovery.flags.Flags;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
@@ -42,7 +44,9 @@ import com.android.internal.util.Preconditions;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;

/**
 * A service to provide packages supporting explicit health checks and route checks to these
@@ -89,11 +93,10 @@ public abstract class ExplicitHealthCheckService extends Service {

    /**
     * {@link Bundle} key for a {@link String} value.
     *
     * {@hide}
     */
    @FlaggedApi(Flags.FLAG_ENABLE_CRASHRECOVERY)
    public static final String EXTRA_HEALTH_CHECK_PASSED_PACKAGE =
            "android.service.watchdog.extra.health_check_passed_package";
            "android.service.watchdog.extra.HEALTH_CHECK_PASSED_PACKAGE";

    /**
     * The Intent action that a service must respond to. Add it to the intent filter of the service
@@ -152,7 +155,8 @@ public abstract class ExplicitHealthCheckService extends Service {
    @NonNull public abstract List<String> onGetRequestedPackages();

    private final Handler mHandler = Handler.createAsync(Looper.getMainLooper());
    @Nullable private RemoteCallback mCallback;
    @Nullable private Consumer<Bundle> mHealthCheckResultCallback;
    @Nullable private Executor mCallbackExecutor;

    @Override
    @NonNull
@@ -161,30 +165,49 @@ public abstract class ExplicitHealthCheckService extends Service {
    }

    /**
     * Sets {@link RemoteCallback}, for testing purpose.
     * Sets a callback to be invoked when an explicit health check passes for a package.
     * <p>
     * The callback will receive a {@link Bundle} containing the package name that passed the
     * health check, identified by the key {@link #EXTRA_HEALTH_CHECK_PASSED_PACKAGE}.
     * <p>
     * <b>Note:</b> This API is primarily intended for testing purposes. Calling this outside of a
     * test environment will override the default callback mechanism used to notify the system
     * about health check results. Use with caution in production code.
     *
     * @hide
     * @param executor The executor on which the callback should be invoked. If {@code null}, the
     *                 callback will be executed on the main thread.
     * @param callback A callback that receives a {@link Bundle} containing the package name that
     *                 passed the health check.
     */
    @TestApi
    public void setCallback(@Nullable RemoteCallback callback) {
        mCallback = callback;
    @FlaggedApi(Flags.FLAG_ENABLE_CRASHRECOVERY)
    public final void setHealthCheckResultCallback(@CallbackExecutor @Nullable Executor executor,
            @Nullable Consumer<Bundle> callback) {
        mCallbackExecutor = executor;
        mHealthCheckResultCallback = callback;
    }
    /**
     * Implementors should call this to notify the system when explicit health check passes
     * for {@code packageName};
     */
    public final void notifyHealthCheckPassed(@NonNull String packageName) {
        mHandler.post(() -> {
            if (mCallback != null) {

    private void executeCallback(@NonNull String packageName) {
        if (mHealthCheckResultCallback != null) {
            Objects.requireNonNull(packageName,
                    "Package passing explicit health check must be non-null");
            Bundle bundle = new Bundle();
            bundle.putString(EXTRA_HEALTH_CHECK_PASSED_PACKAGE, packageName);
                mCallback.sendResult(bundle);
            mHealthCheckResultCallback.accept(bundle);
        } else {
            Log.wtf(TAG, "System missed explicit health check result for " + packageName);
        }
        });
    }

    /**
     * Implementors should call this to notify the system when explicit health check passes
     * for {@code packageName};
     */
    public final void notifyHealthCheckPassed(@NonNull String packageName) {
        if (mCallbackExecutor != null) {
            mCallbackExecutor.execute(() -> executeCallback(packageName));
        } else {
            mHandler.post(() -> executeCallback(packageName));
        }
    }

    /**
@@ -296,9 +319,7 @@ public abstract class ExplicitHealthCheckService extends Service {
    private class ExplicitHealthCheckServiceWrapper extends IExplicitHealthCheckService.Stub {
        @Override
        public void setCallback(RemoteCallback callback) throws RemoteException {
            mHandler.post(() -> {
                mCallback = callback;
            });
            mHandler.post(() -> mHealthCheckResultCallback = callback::sendResult);
        }

        @Override
+3 −3
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@

package com.android.server;

import static android.service.watchdog.ExplicitHealthCheckService.EXTRA_HEALTH_CHECK_PASSED_PACKAGE;

import static com.google.common.truth.Truth.assertThat;

import static org.mockito.Mockito.spy;
@@ -35,8 +37,6 @@ public class ExplicitHealthCheckServiceTest {

    private ExplicitHealthCheckService mExplicitHealthCheckService;
    private static final String PACKAGE_NAME = "com.test.package";
    private static final String EXTRA_HEALTH_CHECK_PASSED_PACKAGE =
            "android.service.watchdog.extra.health_check_passed_package";

    @Before
    public void setup() throws Exception {
@@ -52,7 +52,7 @@ public class ExplicitHealthCheckServiceTest {
        IBinder binder = mExplicitHealthCheckService.onBind(new Intent());
        CountDownLatch countDownLatch = new CountDownLatch(1);
        RemoteCallback callback = new RemoteCallback(result -> {
            assertThat(result.get(EXTRA_HEALTH_CHECK_PASSED_PACKAGE))
            assertThat(result.getString(EXTRA_HEALTH_CHECK_PASSED_PACKAGE))
                    .isEqualTo(PACKAGE_NAME);
            countDownLatch.countDown();
        });