Loading services/core/java/com/android/server/appbinding/AppBindingService.java +44 −36 Original line number Diff line number Diff line Loading @@ -21,7 +21,6 @@ import android.annotation.Nullable; import android.app.AppGlobals; import android.app.supervision.flags.Flags; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; Loading @@ -32,7 +31,6 @@ import android.database.ContentObserver; import android.net.Uri; import android.os.Binder; import android.os.Handler; import android.os.IBinder; import android.os.IInterface; import android.os.UserHandle; import android.provider.Settings; Loading @@ -46,8 +44,6 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.os.BackgroundThread; import com.android.internal.util.DumpUtils; import com.android.server.SystemService; import com.android.server.SystemService.TargetUser; import com.android.server.am.PersistentConnection; import com.android.server.appbinding.finders.AppServiceFinder; import com.android.server.appbinding.finders.CarrierMessagingClientServiceFinder; import com.android.server.appbinding.finders.SupervisionAppServiceFinder; Loading @@ -55,12 +51,13 @@ import com.android.server.appbinding.finders.SupervisionAppServiceFinder; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; import java.util.List; import java.util.function.Consumer; /** * System server that keeps a binding to an app to keep it always running. * * <p>As of android Q, we only use it for the default SMS app. * <p>We only use it for the default SMS app and the Supervision App. * * Relevant tests: * atest CtsAppBindingHostTestCases Loading Loading @@ -120,6 +117,7 @@ public class AppBindingService extends Binder { @Override public void onStart() { publishBinderService(Context.APP_BINDING_SERVICE, mService); publishLocalService(AppBindingService.class, mService); } @Override Loading @@ -143,6 +141,46 @@ public class AppBindingService extends Binder { } } /** Get the list of services bound to a specific finder class. */ public <T extends IInterface> List<AppServiceConnection> getAppServiceConnections( Class<? extends AppServiceFinder<?, T>> appServiceFinderClass, int userId) { List<AppServiceConnection> serviceConnections = new ArrayList<>(); synchronized (mLock) { for (int i = 0; i < mApps.size(); i++) { final AppServiceFinder app = mApps.get(i); if (app.getClass() != appServiceFinderClass) { continue; } AppServiceConnection conn = getBoundConnectionLocked(userId, app); if (conn != null) { serviceConnections.add(conn); } } } return serviceConnections; } /** Get the connection bound to a specific finder. If the connection does not * already exist, create one. */ private AppServiceConnection getBoundConnectionLocked(int userId, AppServiceFinder app) { AppServiceConnection conn = findConnectionLock(userId, app); if (conn == null) { final ServiceInfo service = app.findService(userId, mIPackageManager, mConstants); if (service==null) { Slog.d(TAG, "Can't create connection with app " + app.getTargetPackage(userId) + ". Service is null."); return null; } conn = new AppServiceConnection( mContext, userId, mConstants, mHandler, app, service.getComponentName()); } mConnections.add(conn); conn.bind(); return conn; } private AppBindingService(Injector injector, Context context) { mInjector = injector; mContext = context; Loading Loading @@ -332,6 +370,7 @@ public class AppBindingService extends Binder { if (DEBUG) { Slog.d(TAG, "onAppChanged: u" + userId + " " + finder.getAppDescription()); } synchronized (mLock) { final String reason = finder.getAppDescription() + " changed"; unbindServicesLocked(userId, finder, reason); Loading Loading @@ -435,37 +474,6 @@ public class AppBindingService extends Binder { } } private static class AppServiceConnection extends PersistentConnection<IInterface> { private final AppBindingConstants mConstants; private final AppServiceFinder mFinder; AppServiceConnection(Context context, int userId, AppBindingConstants constants, Handler handler, AppServiceFinder finder, @NonNull ComponentName componentName) { super(TAG, context, handler, userId, componentName, constants.SERVICE_RECONNECT_BACKOFF_SEC, constants.SERVICE_RECONNECT_BACKOFF_INCREASE, constants.SERVICE_RECONNECT_MAX_BACKOFF_SEC, constants.SERVICE_STABLE_CONNECTION_THRESHOLD_SEC); mFinder = finder; mConstants = constants; } @Override protected int getBindFlags() { return mFinder.getBindFlags(mConstants); } @Override protected IInterface asInterface(IBinder obj) { return mFinder.asInterface(obj); } public AppServiceFinder getFinder() { return mFinder; } } @Override public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return; Loading services/core/java/com/android/server/appbinding/AppServiceConnection.java 0 → 100644 +64 −0 Original line number Diff line number Diff line /* * Copyright (C) 2025 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.appbinding; import android.annotation.NonNull; import android.content.ComponentName; import android.content.Context; import android.os.Handler; import android.os.IBinder; import android.os.IInterface; import com.android.server.am.PersistentConnection; import com.android.server.appbinding.finders.AppServiceFinder; /** * 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 * default app changes. */ public class AppServiceConnection extends PersistentConnection<IInterface> { public static final String TAG = "AppServiceConnection"; private final AppBindingConstants mConstants; private final AppServiceFinder mFinder; AppServiceConnection(Context context, int userId, AppBindingConstants constants, Handler handler, AppServiceFinder finder, @NonNull ComponentName componentName) { super(TAG, context, handler, userId, componentName, constants.SERVICE_RECONNECT_BACKOFF_SEC, constants.SERVICE_RECONNECT_BACKOFF_INCREASE, constants.SERVICE_RECONNECT_MAX_BACKOFF_SEC, constants.SERVICE_STABLE_CONNECTION_THRESHOLD_SEC); mFinder = finder; mConstants = constants; } @Override protected int getBindFlags() { return mFinder.getBindFlags(mConstants); } @Override protected IInterface asInterface(IBinder obj) { return mFinder.asInterface(obj); } public AppServiceFinder getFinder() { return mFinder; } } services/core/java/com/android/server/appbinding/finders/SupervisionAppServiceFinder.java +0 −11 Original line number Diff line number Diff line Loading @@ -79,11 +79,6 @@ public class SupervisionAppServiceFinder CollectionUtils.firstOrNull( mRoleManager.getRoleHoldersAsUser( RoleManager.ROLE_SYSTEM_SUPERVISION, UserHandle.of(userId))); if (DEBUG) { Slog.d(TAG, "getTargetPackage()=" + ret); } return ret; } Loading @@ -107,12 +102,6 @@ public class SupervisionAppServiceFinder @Override protected String validateService(ServiceInfo service) { final String packageName = service.packageName; final String process = service.processName; if (process == null || TextUtils.equals(packageName, process)) { return "Service must not run on the main process"; } return null; // Null means accept this service. } Loading services/supervision/java/com/android/server/supervision/SupervisionService.java +44 −0 Original line number Diff line number Diff line Loading @@ -31,7 +31,9 @@ import android.annotation.UserIdInt; import android.app.KeyguardManager; import android.app.admin.DevicePolicyManager; import android.app.admin.DevicePolicyManagerInternal; import android.app.supervision.ISupervisionAppService; import android.app.supervision.ISupervisionManager; import android.app.supervision.SupervisionAppService; import android.app.supervision.SupervisionManagerInternal; import android.app.supervision.SupervisionRecoveryInfo; import android.app.supervision.flags.Flags; Loading @@ -48,6 +50,7 @@ import android.os.RemoteException; import android.os.ResultReceiver; import android.os.ShellCallback; import android.os.UserHandle; import android.util.Slog; import android.util.SparseArray; import com.android.internal.R; Loading @@ -57,6 +60,9 @@ import com.android.internal.util.DumpUtils; import com.android.internal.util.IndentingPrintWriter; import com.android.server.LocalServices; import com.android.server.SystemService; import com.android.server.appbinding.AppBindingService; import com.android.server.appbinding.AppServiceConnection; import com.android.server.appbinding.finders.SupervisionAppServiceFinder; import com.android.server.pm.UserManagerInternal; import java.io.FileDescriptor; Loading Loading @@ -119,6 +125,36 @@ public class SupervisionService extends ISupervisionManager.Stub { enforcePermission(INTERACT_ACROSS_USERS); } setSupervisionEnabledForUserInternal(userId, enabled, getSystemSupervisionPackage()); if (Flags.enableSupervisionAppService()) { List<AppServiceConnection> connections = getSupervisionAppServiceConnections(userId); for (AppServiceConnection conn : connections) { String targetPackage = conn.getFinder().getTargetPackage(userId); ISupervisionAppService binder = (ISupervisionAppService) conn.getServiceBinder(); if (binder == null) { Slog.d(LOG_TAG, String.format( "Unable to toggle supervision for package %s. Binder is null.", targetPackage)); continue; } try { if (enabled) { binder.onEnabled(); } else { binder.onDisabled(); } } catch (RemoteException e) { Slog.d(LOG_TAG, String.format( "Unable to toggle supervision for package %s. e = %s", targetPackage, e)); } } } } private List<AppServiceConnection> getSupervisionAppServiceConnections(@UserIdInt int userId) { AppBindingService abs = mInjector.getAppBindingService(); return abs.getAppServiceConnections(SupervisionAppServiceFinder.class, userId); } /** Loading Loading @@ -345,6 +381,7 @@ public class SupervisionService extends ISupervisionManager.Stub { static class Injector { private final Context mContext; private DevicePolicyManagerInternal mDpmInternal; private AppBindingService mAppBindingService; private KeyguardManager mKeyguardManager; private PackageManager mPackageManager; private UserManagerInternal mUserManagerInternal; Loading @@ -353,6 +390,13 @@ public class SupervisionService extends ISupervisionManager.Stub { mContext = context; } AppBindingService getAppBindingService() { if (mAppBindingService == null) { mAppBindingService = LocalServices.getService(AppBindingService.class); } return mAppBindingService; } @Nullable DevicePolicyManagerInternal getDpmInternal() { if (mDpmInternal == null) { Loading Loading
services/core/java/com/android/server/appbinding/AppBindingService.java +44 −36 Original line number Diff line number Diff line Loading @@ -21,7 +21,6 @@ import android.annotation.Nullable; import android.app.AppGlobals; import android.app.supervision.flags.Flags; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; Loading @@ -32,7 +31,6 @@ import android.database.ContentObserver; import android.net.Uri; import android.os.Binder; import android.os.Handler; import android.os.IBinder; import android.os.IInterface; import android.os.UserHandle; import android.provider.Settings; Loading @@ -46,8 +44,6 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.os.BackgroundThread; import com.android.internal.util.DumpUtils; import com.android.server.SystemService; import com.android.server.SystemService.TargetUser; import com.android.server.am.PersistentConnection; import com.android.server.appbinding.finders.AppServiceFinder; import com.android.server.appbinding.finders.CarrierMessagingClientServiceFinder; import com.android.server.appbinding.finders.SupervisionAppServiceFinder; Loading @@ -55,12 +51,13 @@ import com.android.server.appbinding.finders.SupervisionAppServiceFinder; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; import java.util.List; import java.util.function.Consumer; /** * System server that keeps a binding to an app to keep it always running. * * <p>As of android Q, we only use it for the default SMS app. * <p>We only use it for the default SMS app and the Supervision App. * * Relevant tests: * atest CtsAppBindingHostTestCases Loading Loading @@ -120,6 +117,7 @@ public class AppBindingService extends Binder { @Override public void onStart() { publishBinderService(Context.APP_BINDING_SERVICE, mService); publishLocalService(AppBindingService.class, mService); } @Override Loading @@ -143,6 +141,46 @@ public class AppBindingService extends Binder { } } /** Get the list of services bound to a specific finder class. */ public <T extends IInterface> List<AppServiceConnection> getAppServiceConnections( Class<? extends AppServiceFinder<?, T>> appServiceFinderClass, int userId) { List<AppServiceConnection> serviceConnections = new ArrayList<>(); synchronized (mLock) { for (int i = 0; i < mApps.size(); i++) { final AppServiceFinder app = mApps.get(i); if (app.getClass() != appServiceFinderClass) { continue; } AppServiceConnection conn = getBoundConnectionLocked(userId, app); if (conn != null) { serviceConnections.add(conn); } } } return serviceConnections; } /** Get the connection bound to a specific finder. If the connection does not * already exist, create one. */ private AppServiceConnection getBoundConnectionLocked(int userId, AppServiceFinder app) { AppServiceConnection conn = findConnectionLock(userId, app); if (conn == null) { final ServiceInfo service = app.findService(userId, mIPackageManager, mConstants); if (service==null) { Slog.d(TAG, "Can't create connection with app " + app.getTargetPackage(userId) + ". Service is null."); return null; } conn = new AppServiceConnection( mContext, userId, mConstants, mHandler, app, service.getComponentName()); } mConnections.add(conn); conn.bind(); return conn; } private AppBindingService(Injector injector, Context context) { mInjector = injector; mContext = context; Loading Loading @@ -332,6 +370,7 @@ public class AppBindingService extends Binder { if (DEBUG) { Slog.d(TAG, "onAppChanged: u" + userId + " " + finder.getAppDescription()); } synchronized (mLock) { final String reason = finder.getAppDescription() + " changed"; unbindServicesLocked(userId, finder, reason); Loading Loading @@ -435,37 +474,6 @@ public class AppBindingService extends Binder { } } private static class AppServiceConnection extends PersistentConnection<IInterface> { private final AppBindingConstants mConstants; private final AppServiceFinder mFinder; AppServiceConnection(Context context, int userId, AppBindingConstants constants, Handler handler, AppServiceFinder finder, @NonNull ComponentName componentName) { super(TAG, context, handler, userId, componentName, constants.SERVICE_RECONNECT_BACKOFF_SEC, constants.SERVICE_RECONNECT_BACKOFF_INCREASE, constants.SERVICE_RECONNECT_MAX_BACKOFF_SEC, constants.SERVICE_STABLE_CONNECTION_THRESHOLD_SEC); mFinder = finder; mConstants = constants; } @Override protected int getBindFlags() { return mFinder.getBindFlags(mConstants); } @Override protected IInterface asInterface(IBinder obj) { return mFinder.asInterface(obj); } public AppServiceFinder getFinder() { return mFinder; } } @Override public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return; Loading
services/core/java/com/android/server/appbinding/AppServiceConnection.java 0 → 100644 +64 −0 Original line number Diff line number Diff line /* * Copyright (C) 2025 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.appbinding; import android.annotation.NonNull; import android.content.ComponentName; import android.content.Context; import android.os.Handler; import android.os.IBinder; import android.os.IInterface; import com.android.server.am.PersistentConnection; import com.android.server.appbinding.finders.AppServiceFinder; /** * 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 * default app changes. */ public class AppServiceConnection extends PersistentConnection<IInterface> { public static final String TAG = "AppServiceConnection"; private final AppBindingConstants mConstants; private final AppServiceFinder mFinder; AppServiceConnection(Context context, int userId, AppBindingConstants constants, Handler handler, AppServiceFinder finder, @NonNull ComponentName componentName) { super(TAG, context, handler, userId, componentName, constants.SERVICE_RECONNECT_BACKOFF_SEC, constants.SERVICE_RECONNECT_BACKOFF_INCREASE, constants.SERVICE_RECONNECT_MAX_BACKOFF_SEC, constants.SERVICE_STABLE_CONNECTION_THRESHOLD_SEC); mFinder = finder; mConstants = constants; } @Override protected int getBindFlags() { return mFinder.getBindFlags(mConstants); } @Override protected IInterface asInterface(IBinder obj) { return mFinder.asInterface(obj); } public AppServiceFinder getFinder() { return mFinder; } }
services/core/java/com/android/server/appbinding/finders/SupervisionAppServiceFinder.java +0 −11 Original line number Diff line number Diff line Loading @@ -79,11 +79,6 @@ public class SupervisionAppServiceFinder CollectionUtils.firstOrNull( mRoleManager.getRoleHoldersAsUser( RoleManager.ROLE_SYSTEM_SUPERVISION, UserHandle.of(userId))); if (DEBUG) { Slog.d(TAG, "getTargetPackage()=" + ret); } return ret; } Loading @@ -107,12 +102,6 @@ public class SupervisionAppServiceFinder @Override protected String validateService(ServiceInfo service) { final String packageName = service.packageName; final String process = service.processName; if (process == null || TextUtils.equals(packageName, process)) { return "Service must not run on the main process"; } return null; // Null means accept this service. } Loading
services/supervision/java/com/android/server/supervision/SupervisionService.java +44 −0 Original line number Diff line number Diff line Loading @@ -31,7 +31,9 @@ import android.annotation.UserIdInt; import android.app.KeyguardManager; import android.app.admin.DevicePolicyManager; import android.app.admin.DevicePolicyManagerInternal; import android.app.supervision.ISupervisionAppService; import android.app.supervision.ISupervisionManager; import android.app.supervision.SupervisionAppService; import android.app.supervision.SupervisionManagerInternal; import android.app.supervision.SupervisionRecoveryInfo; import android.app.supervision.flags.Flags; Loading @@ -48,6 +50,7 @@ import android.os.RemoteException; import android.os.ResultReceiver; import android.os.ShellCallback; import android.os.UserHandle; import android.util.Slog; import android.util.SparseArray; import com.android.internal.R; Loading @@ -57,6 +60,9 @@ import com.android.internal.util.DumpUtils; import com.android.internal.util.IndentingPrintWriter; import com.android.server.LocalServices; import com.android.server.SystemService; import com.android.server.appbinding.AppBindingService; import com.android.server.appbinding.AppServiceConnection; import com.android.server.appbinding.finders.SupervisionAppServiceFinder; import com.android.server.pm.UserManagerInternal; import java.io.FileDescriptor; Loading Loading @@ -119,6 +125,36 @@ public class SupervisionService extends ISupervisionManager.Stub { enforcePermission(INTERACT_ACROSS_USERS); } setSupervisionEnabledForUserInternal(userId, enabled, getSystemSupervisionPackage()); if (Flags.enableSupervisionAppService()) { List<AppServiceConnection> connections = getSupervisionAppServiceConnections(userId); for (AppServiceConnection conn : connections) { String targetPackage = conn.getFinder().getTargetPackage(userId); ISupervisionAppService binder = (ISupervisionAppService) conn.getServiceBinder(); if (binder == null) { Slog.d(LOG_TAG, String.format( "Unable to toggle supervision for package %s. Binder is null.", targetPackage)); continue; } try { if (enabled) { binder.onEnabled(); } else { binder.onDisabled(); } } catch (RemoteException e) { Slog.d(LOG_TAG, String.format( "Unable to toggle supervision for package %s. e = %s", targetPackage, e)); } } } } private List<AppServiceConnection> getSupervisionAppServiceConnections(@UserIdInt int userId) { AppBindingService abs = mInjector.getAppBindingService(); return abs.getAppServiceConnections(SupervisionAppServiceFinder.class, userId); } /** Loading Loading @@ -345,6 +381,7 @@ public class SupervisionService extends ISupervisionManager.Stub { static class Injector { private final Context mContext; private DevicePolicyManagerInternal mDpmInternal; private AppBindingService mAppBindingService; private KeyguardManager mKeyguardManager; private PackageManager mPackageManager; private UserManagerInternal mUserManagerInternal; Loading @@ -353,6 +390,13 @@ public class SupervisionService extends ISupervisionManager.Stub { mContext = context; } AppBindingService getAppBindingService() { if (mAppBindingService == null) { mAppBindingService = LocalServices.getService(AppBindingService.class); } return mAppBindingService; } @Nullable DevicePolicyManagerInternal getDpmInternal() { if (mDpmInternal == null) { Loading