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

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

Merge "Invoke SupervisionAppService callbacks whenever supervision state changes" into main

parents e3a475ae f9f68d82
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) {