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

Commit ba2d71ea authored by Cintia Martins's avatar Cintia Martins
Browse files

Create method dispatchAppServiceEvent in AppBindingService

Bug: 441932377
Bug: 441152612
Test: atest SupervisionServiceTest
Test: atest CtsSupervisionTestCases
Flag: android.app.supervision.flags.enable_app_service_connection_callback
Change-Id: Iaad181feefd4db38e5775090fca53717df00c0aa
parent 1335dcb3
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -123,3 +123,11 @@ flag {
    description: "Flag that enables app store filters screen with Supervision settings entry point"
    bug: "438298503"
}

flag {
  name: "enable_app_service_connection_callback"
  is_exported: false
  namespace: "supervision"
  description: "Enables AppBindingService to dispatch actions to be executed by AppServiceConnection after a connection is established."
  bug: "441932377"
}
+20 −0
Original line number Diff line number Diff line
@@ -178,6 +178,26 @@ public class AppBindingService extends Binder {
        return boundConnections;
    }


    public <T> void dispatchAppServiceEvent(
            Class<? extends AppServiceFinder<?, ?>> finderClass,
            int userId, Consumer<AppServiceConnection> action) {
        List<AppServiceConnection> serviceConnections = new ArrayList<>();
        synchronized (mLock) {
            for (int i = 0; i < mApps.size(); i++) {
                final AppServiceFinder app = mApps.get(i);
                if (app.getClass() != finderClass) {
                    continue;
                }
                serviceConnections.addAll(getConnectionsLocked(userId, app));
            }
        }
        for (AppServiceConnection conn: serviceConnections) {
            conn.addCallback(action);
            conn.bind();
        }
    }

    /**
     * Get the connection bound to a specific finder or create one if it does not exist.
     */
+59 −4
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package com.android.server.appbinding;

import android.annotation.NonNull;
import android.app.supervision.flags.Flags;
import android.content.ComponentName;
import android.content.Context;
import android.os.ConditionVariable;
@@ -24,10 +25,16 @@ import android.os.Handler;
import android.os.IBinder;
import android.os.IInterface;

import com.android.internal.annotations.GuardedBy;
import com.android.server.am.PersistentConnection;
import com.android.server.appbinding.finders.AppServiceFinder;
import com.android.server.utils.Slogf;

import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Queue;
import java.util.function.Consumer;

/**
 * Establishes a persistent connection to a given service component for a given user
 * Each connection is associated with an AppServiceFinder to facilitate the service exchange if the
@@ -39,6 +46,10 @@ public class AppServiceConnection extends PersistentConnection<IInterface> {
    private final AppServiceFinder mFinder;
    private final String mPackageName;
    private final ConditionVariable mConditionVariable = new ConditionVariable();
    private final Handler mHandler;
    @GuardedBy("mLock")
    private final Queue<Consumer<AppServiceConnection>> mCallbacks = new ArrayDeque<>();
    private final Object mLock = new Object();

    AppServiceConnection(Context context, int userId, AppBindingConstants constants,
            Handler handler, AppServiceFinder finder, String packageName,
@@ -51,6 +62,7 @@ public class AppServiceConnection extends PersistentConnection<IInterface> {
        mFinder = finder;
        mConstants = constants;
        mPackageName = packageName;
        mHandler = handler;
    }

    @Override
@@ -69,13 +81,19 @@ public class AppServiceConnection extends PersistentConnection<IInterface> {

    @Override
    protected void onConnected(@NonNull IInterface service) {
        if (Flags.enableAppServiceConnectionCallback()) {
            scheduleCallbacks();
        } else {
            mConditionVariable.open();
        }
    }

    @Override
    protected void onDisconnected() {
        if (!Flags.enableAppServiceConnectionCallback()) {
            mConditionVariable.close();
        }
    }

    public AppServiceFinder getFinder() {
        return mFinder;
@@ -85,6 +103,40 @@ public class AppServiceConnection extends PersistentConnection<IInterface> {
        return mPackageName;
    }

    /**
     * Adds a callback to the queue and tries to schedule it immediately
     *
     * @param callback The action to be executed
     */
    public void addCallback(Consumer<AppServiceConnection> callback) {
        if (Flags.enableAppServiceConnectionCallback()) {
            synchronized (mLock) {
                mCallbacks.add(callback);
            }
            scheduleCallbacks();
        }
    }

    /**
     * Schedules all callbacks in the queue to be executed in the background if the connection is
     * already established
     */
    private void scheduleCallbacks() {
        if (isConnected()) {
            ArrayList<Consumer<AppServiceConnection>> callbacks;
            synchronized (mLock) {
                callbacks = new ArrayList<>(mCallbacks);
                mCallbacks.clear();
            }

            for (Consumer<AppServiceConnection> action : callbacks) {
                mHandler.post(() -> {
                    action.accept(this);
                });
            }
        }
    }

    /**
     * Establishes the service connection and blocks until the service is connected
     * or a timeout occurs.
@@ -92,7 +144,10 @@ public class AppServiceConnection extends PersistentConnection<IInterface> {
     * @return true if the service connected successfully within the timeout, false otherwise.
     */
    public boolean awaitConnection() {
        if (!Flags.enableAppServiceConnectionCallback()) {
            long timeoutMs = mConstants.SERVICE_RECONNECT_MAX_BACKOFF_SEC * 10 * 1000L;
            return mConditionVariable.block(timeoutMs) && isConnected();
        }
        return isConnected();
    }
}
+57 −16
Original line number Diff line number Diff line
@@ -124,6 +124,7 @@ public class SupervisionService extends ISupervisionManager.Stub {
    // BackgroundThread for its connection callbacks. Using the same thread would block while
    // waiting for those callbacks, preventing the new connections from being perceived.
    final ServiceThread mServiceThread;
    public static final boolean DEBUG = false; // DO NOT SUBMIT WITH TRUE

    @GuardedBy("getLockObject()")
    final SupervisionSettings mSupervisionSettings = SupervisionSettings.getInstance();
@@ -167,6 +168,7 @@ public class SupervisionService extends ISupervisionManager.Stub {
        setSupervisionEnabledForUserInternal(userId, enabled, getSystemSupervisionPackage());
    }

    // TODO(b/444411638): Remove this after enable_app_service_connection_callback rollout
    private List<AppServiceConnection> getSupervisionAppServiceConnections(@UserIdInt int userId) {
        AppBindingService abs = mInjector.getAppBindingService();
        return abs != null
@@ -408,9 +410,7 @@ public class SupervisionService extends ISupervisionManager.Stub {
                mSupervisionSettings.saveUserData();
            }
        }
        mServiceThread
                .getThreadExecutor()
                .execute(
        executeOnSupervisionEnabled(
                () -> {
                    updateWebContentFilters(userId, enabled);
                    dispatchSupervisionEvent(
@@ -424,12 +424,21 @@ public class SupervisionService extends ISupervisionManager.Stub {
                });
    }

    private void executeOnSupervisionEnabled(Runnable runnable) {
        if (Flags.enableAppServiceConnectionCallback()) {
            Binder.withCleanCallingIdentity(runnable::run);
        } else {
            mServiceThread.getThreadExecutor().execute(runnable);
        }
    }

    @NonNull
    // TODO(b/444411638): Remove this after enable_app_service_connection_callback rollout
    private List<ISupervisionListener> getSupervisionAppServiceListeners(
            @UserIdInt int userId,
            @NonNull RemoteExceptionIgnoringConsumer<ISupervisionListener> action) {
        ArrayList<ISupervisionListener> listeners = new ArrayList<>();
        if (!Flags.enableSupervisionAppService()) {
        if (!Flags.enableSupervisionAppService() || Flags.enableAppServiceConnectionCallback()) {
            return listeners;
        }

@@ -460,7 +469,9 @@ public class SupervisionService extends ISupervisionManager.Stub {
    private void dispatchSupervisionEvent(
            @UserIdInt int userId,
            @NonNull RemoteExceptionIgnoringConsumer<ISupervisionListener> action) {

        if (Flags.enableAppServiceConnectionCallback()) {
            dispatchSupervisionAppServiceEvent(userId, action);
        }
        // Add SupervisionAppServices listeners before the platform listeners.
        ArrayList<ISupervisionListener> listeners =
                new ArrayList<>(getSupervisionAppServiceListeners(userId, action));
@@ -477,6 +488,36 @@ public class SupervisionService extends ISupervisionManager.Stub {
        listeners.forEach(action);
    }

    private void dispatchSupervisionAppServiceEvent(
            @UserIdInt int userId,
            @NonNull RemoteExceptionIgnoringConsumer<ISupervisionListener> action) {
        if (!Flags.enableSupervisionAppService()) {
            return;
        }
        AppBindingService abs = mInjector.getAppBindingService();
        if (abs == null) {
            Slogf.e(SupervisionLog.TAG, "AppBindingService is not available.");
            return;
        }

        abs.dispatchAppServiceEvent(SupervisionAppServiceFinder.class, userId, connection -> {
            ISupervisionListener binder = (ISupervisionListener) connection.getServiceBinder();
            String target = connection.getPackageName();
            if (binder == null) {
                if (DEBUG) {
                    Slogf.i(SupervisionLog.TAG,
                            "Failed to connect to SupervisionAppService in %s", target);
                }
            } else {
                if (DEBUG) {
                    Slogf.i(SupervisionLog.TAG,
                            "Connected to SupervisionAppService in %s", target);
                }
                action.accept(binder);
            }
        });
    }

    private void clearAllDevicePoliciesAndSuspendedPackages(@UserIdInt int userId) {
        if (!Flags.enableRemovePoliciesOnSupervisionDisable()) {
            return;