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

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

Invoke SupervisionAppService callbacks whenever supervision state changes

Bug: 392836577
Flag: android.app.supervision.flags.enable_supervision_app_service
Test: CtsAppBindingHostTestCases
Change-Id: Id39f4d0735d95b97cb2e17d56d388ef0cd58fcfd
parent 067d0d32
Loading
Loading
Loading
Loading
+44 −36
Original line number Diff line number Diff line
@@ -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;
@@ -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;
@@ -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;
@@ -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
@@ -120,6 +117,7 @@ public class AppBindingService extends Binder {
        @Override
        public void onStart() {
            publishBinderService(Context.APP_BINDING_SERVICE, mService);
            publishLocalService(AppBindingService.class, mService);
        }

        @Override
@@ -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;
@@ -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);
@@ -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;
+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;
    }
}
+0 −11
Original line number Diff line number Diff line
@@ -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;
    }

@@ -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.
    }

+44 −0
Original line number Diff line number Diff line
@@ -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;
@@ -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;
@@ -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;
@@ -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);
    }

    /**
@@ -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;
@@ -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) {