Loading core/java/android/app/supervision/flags.aconfig +8 −0 Original line number Diff line number Diff line Loading @@ -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" } services/core/java/com/android/server/appbinding/AppBindingService.java +20 −0 Original line number Diff line number Diff line Loading @@ -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. */ Loading services/core/java/com/android/server/appbinding/AppServiceConnection.java +59 −4 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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 Loading @@ -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, Loading @@ -51,6 +62,7 @@ public class AppServiceConnection extends PersistentConnection<IInterface> { mFinder = finder; mConstants = constants; mPackageName = packageName; mHandler = handler; } @Override Loading @@ -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; Loading @@ -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. Loading @@ -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(); } } services/supervision/java/com/android/server/supervision/SupervisionService.java +57 −16 Original line number Diff line number Diff line Loading @@ -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(); Loading Loading @@ -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 Loading Loading @@ -408,9 +410,7 @@ public class SupervisionService extends ISupervisionManager.Stub { mSupervisionSettings.saveUserData(); } } mServiceThread .getThreadExecutor() .execute( executeOnSupervisionEnabled( () -> { updateWebContentFilters(userId, enabled); dispatchSupervisionEvent( Loading @@ -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; } Loading Loading @@ -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)); Loading @@ -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; Loading Loading
core/java/android/app/supervision/flags.aconfig +8 −0 Original line number Diff line number Diff line Loading @@ -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" }
services/core/java/com/android/server/appbinding/AppBindingService.java +20 −0 Original line number Diff line number Diff line Loading @@ -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. */ Loading
services/core/java/com/android/server/appbinding/AppServiceConnection.java +59 −4 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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 Loading @@ -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, Loading @@ -51,6 +62,7 @@ public class AppServiceConnection extends PersistentConnection<IInterface> { mFinder = finder; mConstants = constants; mPackageName = packageName; mHandler = handler; } @Override Loading @@ -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; Loading @@ -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. Loading @@ -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(); } }
services/supervision/java/com/android/server/supervision/SupervisionService.java +57 −16 Original line number Diff line number Diff line Loading @@ -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(); Loading Loading @@ -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 Loading Loading @@ -408,9 +410,7 @@ public class SupervisionService extends ISupervisionManager.Stub { mSupervisionSettings.saveUserData(); } } mServiceThread .getThreadExecutor() .execute( executeOnSupervisionEnabled( () -> { updateWebContentFilters(userId, enabled); dispatchSupervisionEvent( Loading @@ -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; } Loading Loading @@ -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)); Loading @@ -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; Loading