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

Commit dd218cba authored by Sanjana Sunil's avatar Sanjana Sunil Committed by Android (Google) Code Review
Browse files

Merge "Add support to start and stop SDK sandbox services" into udc-dev

parents 28f4589d 5b04b1c8
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -451,6 +451,15 @@ public final class ApplicationExitInfo implements Parcelable {
     */
    public static final int SUBREASON_SDK_SANDBOX_DIED = 27;

    /**
     * The process was killed because it was an SDK sandbox process that was either not usable or
     * was no longer being used; this would be set only when the reason is {@link #REASON_OTHER}.
     *
     * For internal use only.
     * @hide
     */
    public static final int SUBREASON_SDK_SANDBOX_NOT_NEEDED = 28;

    // If there is any OEM code which involves additional app kill reasons, it should
    // be categorized in {@link #REASON_OTHER}, with subreason code starting from 1000.

+2 −0
Original line number Diff line number Diff line
@@ -1923,6 +1923,7 @@ class ContextImpl extends Context {

    private ComponentName startServiceCommon(Intent service, boolean requireForeground,
            UserHandle user) {
        // Keep this in sync with ActivityManagerLocal.startSdkSandboxService
        try {
            validateServiceIntent(service);
            service.prepareToLeaveProcess(this);
@@ -1964,6 +1965,7 @@ class ContextImpl extends Context {
    }

    private boolean stopServiceCommon(Intent service, UserHandle user) {
        // // Keep this in sync with ActivityManagerLocal.stopSdkSandboxService
        try {
            validateServiceIntent(service);
            service.prepareToLeaveProcess(this);
+2 −0
Original line number Diff line number Diff line
@@ -43,6 +43,8 @@ package com.android.server.am {
    method @Deprecated public boolean bindSdkSandboxService(@NonNull android.content.Intent, @NonNull android.content.ServiceConnection, int, @NonNull String, @NonNull String, int) throws android.os.RemoteException;
    method public boolean canStartForegroundService(int, int, @NonNull String);
    method public void killSdkSandboxClientAppProcess(@NonNull android.os.IBinder);
    method @Nullable public android.content.ComponentName startSdkSandboxService(@NonNull android.content.Intent, int, @NonNull String, @NonNull String) throws android.os.RemoteException;
    method public boolean stopSdkSandboxService(@NonNull android.content.Intent, int, @NonNull String, @NonNull String);
  }

}
+47 −17
Original line number Diff line number Diff line
@@ -746,10 +746,13 @@ public final class ActiveServices {

    ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
            int callingPid, int callingUid, boolean fgRequired, String callingPackage,
            @Nullable String callingFeatureId, final int userId)
            @Nullable String callingFeatureId, final int userId, boolean isSdkSandboxService,
            int sdkSandboxClientAppUid, String sdkSandboxClientAppPackage, String instanceName)
            throws TransactionTooLargeException {
        return startServiceLocked(caller, service, resolvedType, callingPid, callingUid, fgRequired,
                callingPackage, callingFeatureId, userId, BackgroundStartPrivileges.NONE);
                callingPackage, callingFeatureId, userId, BackgroundStartPrivileges.NONE,
                isSdkSandboxService, sdkSandboxClientAppUid, sdkSandboxClientAppPackage,
                instanceName);
    }

    ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
@@ -757,6 +760,17 @@ public final class ActiveServices {
            String callingPackage, @Nullable String callingFeatureId, final int userId,
            BackgroundStartPrivileges backgroundStartPrivileges)
            throws TransactionTooLargeException {
        return startServiceLocked(caller, service, resolvedType, callingPid, callingUid, fgRequired,
                callingPackage, callingFeatureId, userId, backgroundStartPrivileges,
                false /* isSdkSandboxService */, INVALID_UID, null, null);
    }

    ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
            int callingPid, int callingUid, boolean fgRequired,
            String callingPackage, @Nullable String callingFeatureId, final int userId,
            BackgroundStartPrivileges backgroundStartPrivileges, boolean isSdkSandboxService,
            int sdkSandboxClientAppUid, String sdkSandboxClientAppPackage, String instanceName)
            throws TransactionTooLargeException {
        if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "startService: " + service
                + " type=" + resolvedType + " args=" + service.getExtras());

@@ -774,9 +788,9 @@ public final class ActiveServices {
            callerFg = true;
        }

        ServiceLookupResult res =
            retrieveServiceLocked(service, null, resolvedType, callingPackage,
                    callingPid, callingUid, userId, true, callerFg, false, false, false);
        ServiceLookupResult res = retrieveServiceLocked(service, instanceName, isSdkSandboxService,
                sdkSandboxClientAppUid, sdkSandboxClientAppPackage, resolvedType, callingPackage,
                callingPid, callingUid, userId, true, callerFg, false, false, null, false);
        if (res == null) {
            return null;
        }
@@ -800,16 +814,30 @@ public final class ActiveServices {
            return null;
        }

        // For the SDK sandbox, we start the service on behalf of the client app.
        final int appUid = isSdkSandboxService ? sdkSandboxClientAppUid : r.appInfo.uid;
        final String appPackageName =
                isSdkSandboxService ? sdkSandboxClientAppPackage : r.packageName;
        int appTargetSdkVersion = r.appInfo.targetSdkVersion;
        if (isSdkSandboxService) {
            try {
                appTargetSdkVersion = AppGlobals.getPackageManager().getApplicationInfo(
                        appPackageName, ActivityManagerService.STOCK_PM_FLAGS,
                        userId).targetSdkVersion;
            } catch (RemoteException ignored) {
            }
        }

        // If we're starting indirectly (e.g. from PendingIntent), figure out whether
        // we're launching into an app in a background state.  This keys off of the same
        // idleness state tracking as e.g. O+ background service start policy.
        final boolean bgLaunch = !mAm.isUidActiveLOSP(r.appInfo.uid);
        final boolean bgLaunch = !mAm.isUidActiveLOSP(appUid);

        // If the app has strict background restrictions, we treat any bg service
        // start analogously to the legacy-app forced-restrictions case, regardless
        // of its target SDK version.
        boolean forcedStandby = false;
        if (bgLaunch && appRestrictedAnyInBackground(r.appInfo.uid, r.packageName)) {
        if (bgLaunch && appRestrictedAnyInBackground(appUid, appPackageName)) {
            if (DEBUG_FOREGROUND_SERVICE) {
                Slog.d(TAG, "Forcing bg-only service start only for " + r.shortInstanceName
                        + " : bgLaunch=" + bgLaunch + " callerFg=" + callerFg);
@@ -839,7 +867,7 @@ public final class ActiveServices {
        boolean forceSilentAbort = false;
        if (fgRequired) {
            final int mode = mAm.getAppOpsManager().checkOpNoThrow(
                    AppOpsManager.OP_START_FOREGROUND, r.appInfo.uid, r.packageName);
                    AppOpsManager.OP_START_FOREGROUND, appUid, appPackageName);
            switch (mode) {
                case AppOpsManager.MODE_ALLOWED:
                case AppOpsManager.MODE_DEFAULT:
@@ -861,12 +889,12 @@ public final class ActiveServices {
        }

        // If this isn't a direct-to-foreground start, check our ability to kick off an
        // arbitrary service
        // arbitrary service.
        if (forcedStandby || (!r.startRequested && !fgRequired)) {
            // Before going further -- if this app is not allowed to start services in the
            // background, then at this point we aren't going to let it period.
            final int allowed = mAm.getAppStartModeLOSP(r.appInfo.uid, r.packageName,
                    r.appInfo.targetSdkVersion, callingPid, false, false, forcedStandby);
            final int allowed = mAm.getAppStartModeLOSP(appUid, appPackageName, appTargetSdkVersion,
                    callingPid, false, false, forcedStandby);
            if (allowed != ActivityManager.APP_START_MODE_NORMAL) {
                Slog.w(TAG, "Background start not allowed: service "
                        + service + " to " + r.shortInstanceName
@@ -890,7 +918,7 @@ public final class ActiveServices {
                }
                // This app knows it is in the new model where this operation is not
                // allowed, so tell it what has happened.
                UidRecord uidRec = mAm.mProcessList.getUidRecordLOSP(r.appInfo.uid);
                UidRecord uidRec = mAm.mProcessList.getUidRecordLOSP(appUid);
                return new ComponentName("?", "app is in background uid " + uidRec);
            }
        }
@@ -899,10 +927,10 @@ public final class ActiveServices {
        // an ordinary startService() or a startForegroundService().  Now, only require that
        // the app follow through on the startForegroundService() -> startForeground()
        // contract if it actually targets O+.
        if (r.appInfo.targetSdkVersion < Build.VERSION_CODES.O && fgRequired) {
        if (appTargetSdkVersion < Build.VERSION_CODES.O && fgRequired) {
            if (DEBUG_BACKGROUND_CHECK || DEBUG_FOREGROUND_SERVICE) {
                Slog.i(TAG, "startForegroundService() but host targets "
                        + r.appInfo.targetSdkVersion + " - not requiring startForeground()");
                        + appTargetSdkVersion + " - not requiring startForeground()");
            }
            fgRequired = false;
        }
@@ -1376,7 +1404,8 @@ public final class ActiveServices {
    }

    int stopServiceLocked(IApplicationThread caller, Intent service,
            String resolvedType, int userId) {
            String resolvedType, int userId, boolean isSdkSandboxService,
            int sdkSandboxClientAppUid, String sdkSandboxClientAppPackage, String instanceName) {
        if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "stopService: " + service
                + " type=" + resolvedType);

@@ -1389,9 +1418,10 @@ public final class ActiveServices {
        }

        // If this service is active, make sure it is stopped.
        ServiceLookupResult r = retrieveServiceLocked(service, null, resolvedType, null,
        ServiceLookupResult r = retrieveServiceLocked(service, instanceName, isSdkSandboxService,
                sdkSandboxClientAppUid, sdkSandboxClientAppPackage, resolvedType, null,
                Binder.getCallingPid(), Binder.getCallingUid(), userId, false, false, false, false,
                false);
                null, false);
        if (r != null) {
            if (r.record != null) {
                final long origId = Binder.clearCallingIdentity();
+50 −4
Original line number Diff line number Diff line
@@ -17,8 +17,10 @@
package com.android.server.am;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.content.ComponentName;
import android.content.Context;
import android.content.Context.BindServiceFlags;
import android.content.Context.BindServiceFlagsBits;
@@ -68,9 +70,53 @@ public interface ActivityManagerLocal {
    void tempAllowWhileInUsePermissionInFgs(int uid, long durationMs);

    /**
     * Binds to a sdk sandbox service, creating it if needed. You can through the arguments
     * here have the system bring up multiple concurrent processes hosting their own instance of
     * that service. The {@code processName} you provide here identifies the different instances.
     * Requests that an SDK sandbox service be started. If this service is not already running,
     * it will be instantiated and started (creating a process for it if needed). You can through
     * the arguments here have the system bring up multiple concurrent processes hosting their own
     * instance of that service. Each instance is identified by the {@code processName} provided
     * here.
     *
     * @param service Identifies the sdk sandbox process service to connect to. The Intent must
     *                specify an explicit component name. This value cannot be null.
     * @param clientAppUid Uid of the app for which the sdk sandbox process needs to be spawned.
     * @param clientAppPackage Package of the app for which the sdk sandbox process needs to
     *        be spawned. This package must belong to the clientAppUid.
     * @param processName Unique identifier for the service instance. Each unique name here will
     *        result in a different service instance being created. Identifiers must only contain
     *        ASCII letters, digits, underscores, and periods.
     *
     * @throws RemoteException If the service could not be started.
     * @return If the service is being started or is already running, the {@link ComponentName} of
     * the actual service that was started is returned; else if the service does not exist null is
     * returned.
     */
    @Nullable
    @SuppressLint("RethrowRemoteException")
    ComponentName startSdkSandboxService(@NonNull Intent service, int clientAppUid,
            @NonNull String clientAppPackage, @NonNull String processName)
            throws RemoteException;

    // TODO(b/269592470): What if the sandbox is stopped while there is an active binding to it?
    /**
     * Requests that an SDK sandbox service with a given {@code processName} be stopped.
     *
     * @param service Identifies the sdk sandbox process service to connect to. The Intent must
     *        specify an explicit component name. This value cannot be null.
     * @param clientAppUid Uid of the app for which the sdk sandbox process needs to be stopped.
     * @param clientAppPackage Package of the app for which the sdk sandbox process needs to
     *        be stopped. This package must belong to the clientAppUid.
     * @param processName Unique identifier for the service instance. Each unique name here will
     *        result in a different service instance being created. Identifiers must only contain
     *        ASCII letters, digits, underscores, and periods.
     *
     * @return If there is a service matching the given Intent that is already running, then it is
     *         stopped and true is returned; else false is returned.
     */
    boolean stopSdkSandboxService(@NonNull Intent service, int clientAppUid,
            @NonNull String clientAppPackage, @NonNull String processName);

    /**
     * Binds to an SDK sandbox service for a given client application.
     *
     * @param service Identifies the sdk sandbox process service to connect to. The Intent must
     *        specify an explicit component name. This value cannot be null.
@@ -90,7 +136,7 @@ public interface ActivityManagerLocal {
     *         service that your client has permission to bind to; {@code false}
     *         if the system couldn't find the service or if your client doesn't
     *         have permission to bind to it.
     * @throws RemoteException If the service could not be brought up.
     * @throws RemoteException If the service could not be bound to.
     * @see Context#bindService(Intent, ServiceConnection, int)
     */
    @SuppressLint("RethrowRemoteException")
Loading