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

Commit 4a50a939 authored by Cintia Martins's avatar Cintia Martins Committed by Android (Google) Code Review
Browse files

Merge "Create method dispatchAppServiceEvent in AppBindingService" into main

parents e3a28902 ba2d71ea
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;