diff options
author | 2023-01-25 18:33:11 +0000 | |
---|---|---|
committer | 2023-02-21 17:25:22 +0000 | |
commit | 5b04b1c8667d684afc323a16abeec2a4a5ec0ec8 (patch) | |
tree | 2bf1a9464806de7c9604ca08e8d6b669f940787e | |
parent | 9d0370089f479107bf4a465370cce2f3a366edf6 (diff) |
Add support to start and stop SDK sandbox services
Starting the sandbox service instead of just binding gives us better
control over the sandbox:
* There is no longer a dependency on using BIND_AUTO_CREATE to create a
sandbox process. Sandbox restarts can therefore be disabled if needed.
* The sandbox can be killed by stopping the service instead of using
killUid(). Therefore, the sandbox can be informed when it is about to
die. Killing multiple sandboxes sharing a uid can also be avoided.
Bug: 239562510
Test: atest SdkSandboxLifecycleHostTest
Change-Id: I5c2302a58beb71b08c4d435625e791006bacd3fb
7 files changed, 226 insertions, 52 deletions
diff --git a/core/java/android/app/ApplicationExitInfo.java b/core/java/android/app/ApplicationExitInfo.java index c628ec4cc56c..d859f3f9e175 100644 --- a/core/java/android/app/ApplicationExitInfo.java +++ b/core/java/android/app/ApplicationExitInfo.java @@ -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. diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index a203ae241d39..1c0be686330d 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -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); diff --git a/services/api/current.txt b/services/api/current.txt index 329dbdf6346f..b55166c30965 100644 --- a/services/api/current.txt +++ b/services/api/current.txt @@ -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); } } diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java index 3a93cb3052de..f45dc130a7ef 100644 --- a/services/core/java/com/android/server/am/ActiveServices.java +++ b/services/core/java/com/android/server/am/ActiveServices.java @@ -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(); diff --git a/services/core/java/com/android/server/am/ActivityManagerLocal.java b/services/core/java/com/android/server/am/ActivityManagerLocal.java index 3f0699002b1c..928af3fa4e81 100644 --- a/services/core/java/com/android/server/am/ActivityManagerLocal.java +++ b/services/core/java/com/android/server/am/ActivityManagerLocal.java @@ -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") diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 6aa49d276391..eab5b2cfac4f 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -215,6 +215,7 @@ import android.app.PendingIntent; import android.app.PendingIntentStats; import android.app.ProcessMemoryState; import android.app.ProfilerInfo; +import android.app.ServiceStartNotAllowedException; import android.app.SyncNotedAppOp; import android.app.WaitResult; import android.app.assist.ActivityId; @@ -13172,6 +13173,15 @@ public class ActivityManagerService extends IActivityManager.Stub String resolvedType, boolean requireForeground, String callingPackage, String callingFeatureId, int userId) throws TransactionTooLargeException { + return startService(caller, service, resolvedType, requireForeground, callingPackage, + callingFeatureId, userId, false /* isSdkSandboxService */, INVALID_UID, null, null); + } + + private ComponentName startService(IApplicationThread caller, Intent service, + String resolvedType, boolean requireForeground, String callingPackage, + String callingFeatureId, int userId, boolean isSdkSandboxService, + int sdkSandboxClientAppUid, String sdkSandboxClientAppPackage, String instanceName) + throws TransactionTooLargeException { enforceNotIsolatedCaller("startService"); enforceAllowedToStartOrBindServiceIfSdkSandbox(service); // Refuse possible leaked file descriptors @@ -13183,6 +13193,11 @@ public class ActivityManagerService extends IActivityManager.Stub throw new IllegalArgumentException("callingPackage cannot be null"); } + if (isSdkSandboxService && instanceName == null) { + throw new IllegalArgumentException("No instance name provided for SDK sandbox process"); + } + validateServiceInstanceName(instanceName); + if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "*** startService: " + service + " type=" + resolvedType + " fg=" + requireForeground); final int callingPid = Binder.getCallingPid(); @@ -13198,7 +13213,9 @@ public class ActivityManagerService extends IActivityManager.Stub synchronized (this) { res = mServices.startServiceLocked(caller, service, resolvedType, callingPid, callingUid, - requireForeground, callingPackage, callingFeatureId, userId); + requireForeground, callingPackage, callingFeatureId, userId, + isSdkSandboxService, sdkSandboxClientAppUid, sdkSandboxClientAppPackage, + instanceName); } } finally { Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); @@ -13207,9 +13224,26 @@ public class ActivityManagerService extends IActivityManager.Stub return res; } + private void validateServiceInstanceName(String instanceName) { + // Ensure that instanceName, which is caller provided, does not contain + // unusual characters. + if (instanceName != null) { + if (!instanceName.matches("[a-zA-Z0-9_.]+")) { + throw new IllegalArgumentException("Illegal instanceName"); + } + } + } + @Override public int stopService(IApplicationThread caller, Intent service, String resolvedType, int userId) { + return stopService(caller, service, resolvedType, userId, false /* isSdkSandboxService */, + INVALID_UID, null, null); + } + + private int stopService(IApplicationThread caller, Intent service, String resolvedType, + int userId, boolean isSdkSandboxService, + int sdkSandboxClientAppUid, String sdkSandboxClientAppPackage, String instanceName) { enforceNotIsolatedCaller("stopService"); // Refuse possible leaked file descriptors if (service != null && service.hasFileDescriptors() == true) { @@ -13221,7 +13255,9 @@ public class ActivityManagerService extends IActivityManager.Stub Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "stopService: " + service); } synchronized (this) { - return mServices.stopServiceLocked(caller, service, resolvedType, userId); + return mServices.stopServiceLocked(caller, service, resolvedType, userId, + isSdkSandboxService, sdkSandboxClientAppUid, sdkSandboxClientAppPackage, + instanceName); } } finally { Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); @@ -13380,17 +13416,7 @@ public class ActivityManagerService extends IActivityManager.Stub throw new IllegalArgumentException("No instance name provided for isolated process"); } - // Ensure that instanceName, which is caller provided, does not contain - // unusual characters. - if (instanceName != null) { - for (int i = 0; i < instanceName.length(); ++i) { - char c = instanceName.charAt(i); - if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') - || (c >= '0' && c <= '9') || c == '_' || c == '.')) { - throw new IllegalArgumentException("Illegal instanceName"); - } - } - } + validateServiceInstanceName(instanceName); try { if (Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) { @@ -17290,6 +17316,53 @@ public class ActivityManagerService extends IActivityManager.Stub } @Override + public ComponentName startSdkSandboxService(Intent service, int clientAppUid, + String clientAppPackage, String processName) throws RemoteException { + validateSdkSandboxParams(service, clientAppUid, clientAppPackage, processName); + // TODO(b/269598719): Is passing the application thread of the system_server alright? + // e.g. the sandbox getting privileged access due to this. + ComponentName cn = ActivityManagerService.this.startService( + mContext.getIApplicationThread(), service, + service.resolveTypeIfNeeded(mContext.getContentResolver()), false, + mContext.getOpPackageName(), mContext.getAttributionTag(), + UserHandle.getUserId(clientAppUid), true, clientAppUid, clientAppPackage, + processName); + if (cn != null) { + if (cn.getPackageName().equals("!")) { + throw new SecurityException( + "Not allowed to start service " + service + + " without permission " + cn.getClassName()); + } else if (cn.getPackageName().equals("!!")) { + throw new SecurityException( + "Unable to start service " + service + + ": " + cn.getClassName()); + } else if (cn.getPackageName().equals("?")) { + throw ServiceStartNotAllowedException.newInstance(false, + "Not allowed to start service " + service + ": " + + cn.getClassName()); + } + } + + return cn; + } + + @Override + public boolean stopSdkSandboxService(Intent service, int clientAppUid, + String clientAppPackage, String processName) { + validateSdkSandboxParams(service, clientAppUid, clientAppPackage, processName); + int res = ActivityManagerService.this.stopService( + mContext.getIApplicationThread(), service, + service.resolveTypeIfNeeded(mContext.getContentResolver()), + UserHandle.getUserId(clientAppUid), true, clientAppUid, clientAppPackage, + processName); + if (res < 0) { + throw new SecurityException( + "Not allowed to stop service " + service); + } + return res != 0; + } + + @Override public boolean bindSdkSandboxService(Intent service, ServiceConnection conn, int clientAppUid, IBinder clientApplicationThread, String clientAppPackage, String processName, int flags) @@ -17311,27 +17384,10 @@ public class ActivityManagerService extends IActivityManager.Stub int clientAppUid, IBinder clientApplicationThread, String clientAppPackage, String processName, long flags) throws RemoteException { - if (service == null) { - throw new IllegalArgumentException("intent is null"); - } + validateSdkSandboxParams(service, clientAppUid, clientAppPackage, processName); if (conn == null) { throw new IllegalArgumentException("connection is null"); } - if (clientAppPackage == null) { - throw new IllegalArgumentException("clientAppPackage is null"); - } - if (processName == null) { - throw new IllegalArgumentException("processName is null"); - } - if (service.getComponent() == null) { - throw new IllegalArgumentException("service must specify explicit component"); - } - if (!UserHandle.isApp(clientAppUid)) { - throw new IllegalArgumentException("uid is not within application range"); - } - if (mAppOpsService.checkPackage(clientAppUid, clientAppPackage) != MODE_ALLOWED) { - throw new IllegalArgumentException("uid does not belong to provided package"); - } Handler handler = mContext.getMainThreadHandler(); IApplicationThread clientApplicationThreadVerified = null; @@ -17364,6 +17420,28 @@ public class ActivityManagerService extends IActivityManager.Stub UserHandle.getUserId(clientAppUid)) != 0; } + private void validateSdkSandboxParams(Intent service, int clientAppUid, + String clientAppPackage, String processName) { + if (service == null) { + throw new IllegalArgumentException("intent is null"); + } + if (clientAppPackage == null) { + throw new IllegalArgumentException("clientAppPackage is null"); + } + if (processName == null) { + throw new IllegalArgumentException("processName is null"); + } + if (service.getComponent() == null) { + throw new IllegalArgumentException("service must specify explicit component"); + } + if (!UserHandle.isApp(clientAppUid)) { + throw new IllegalArgumentException("uid is not within application range"); + } + if (mAppOpsService.checkPackage(clientAppUid, clientAppPackage) != MODE_ALLOWED) { + throw new IllegalArgumentException("uid does not belong to provided package"); + } + } + @Override public boolean bindSdkSandboxService(Intent service, ServiceConnection conn, int clientAppUid, String clientAppPackage, String processName, int flags) diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java index 32db33d3047d..cfe0ee88d125 100644 --- a/services/core/java/com/android/server/am/OomAdjuster.java +++ b/services/core/java/com/android/server/am/OomAdjuster.java @@ -1318,6 +1318,13 @@ public class OomAdjuster { // left sitting around after no longer needed. app.killLocked("isolated not needed", ApplicationExitInfo.REASON_OTHER, ApplicationExitInfo.SUBREASON_ISOLATED_NOT_NEEDED, true); + } else if (app.isSdkSandbox && psr.numberOfRunningServices() <= 0 + && app.getActiveInstrumentation() == null) { + // If this is an SDK sandbox process and there are no services running it, we + // aggressively kill the sandbox as we usually don't want to re-use the same + // sandbox again. + app.killLocked("sandbox not needed", ApplicationExitInfo.REASON_OTHER, + ApplicationExitInfo.SUBREASON_SDK_SANDBOX_NOT_NEEDED, true); } else { // Keeping this process, update its uid. updateAppUidRecLSP(app); |