Add a way to instrument sdk sandbox processes
The following restrictions applies to the instrumentation of the sdk sandbox processes: * Instrumentation must be signed with the same certificate as the client app the instrumented sdk sandbox belongs to. * If there is a running instance of to-be-instrumented sdk sandbox process, then it will be killed before the instrumentation starts. * While instrumentation is running the client app won't be allowed to connect to the instrumented sdk sandbox process. * The --no-restart instrumentation of the sdk sandbox processes is not supported. Bug: 209061624 Test: atest SdkSandboxInprocessTests Change-Id: Ia4b145c091bf8da600a77ea82fc9e3cd97757275
This commit is contained in:
parent
44318af94f
commit
99ba880e55
@ -191,6 +191,8 @@ public class Am extends BaseCommand {
|
||||
instrument.noRestart = true;
|
||||
} else if (opt.equals("--always-check-signature")) {
|
||||
instrument.alwaysCheckSignature = true;
|
||||
} else if (opt.equals("--instrument-sdk-sandbox")) {
|
||||
instrument.instrumentSdkSandbox = true;
|
||||
} else {
|
||||
System.err.println("Error: Unknown option: " + opt);
|
||||
return;
|
||||
|
@ -20,6 +20,7 @@ import static android.app.ActivityManager.INSTR_FLAG_ALWAYS_CHECK_SIGNATURE;
|
||||
import static android.app.ActivityManager.INSTR_FLAG_DISABLE_HIDDEN_API_CHECKS;
|
||||
import static android.app.ActivityManager.INSTR_FLAG_DISABLE_ISOLATED_STORAGE;
|
||||
import static android.app.ActivityManager.INSTR_FLAG_DISABLE_TEST_API_CHECKS;
|
||||
import static android.app.ActivityManager.INSTR_FLAG_INSTRUMENT_SDK_SANDBOX;
|
||||
import static android.app.ActivityManager.INSTR_FLAG_NO_RESTART;
|
||||
|
||||
import android.app.IActivityManager;
|
||||
@ -97,6 +98,7 @@ public class Instrument {
|
||||
// Required
|
||||
public String componentNameArg;
|
||||
public boolean alwaysCheckSignature = false;
|
||||
public boolean instrumentSdkSandbox = false;
|
||||
|
||||
/**
|
||||
* Construct the instrument command runner.
|
||||
@ -524,6 +526,9 @@ public class Instrument {
|
||||
if (alwaysCheckSignature) {
|
||||
flags |= INSTR_FLAG_ALWAYS_CHECK_SIGNATURE;
|
||||
}
|
||||
if (instrumentSdkSandbox) {
|
||||
flags |= INSTR_FLAG_INSTRUMENT_SDK_SANDBOX;
|
||||
}
|
||||
if (!mAm.startInstrumentation(cn, profileFile, flags, args, watcher, connection, userId,
|
||||
abi)) {
|
||||
throw new AndroidException("INSTRUMENTATION_FAILED: " + cn.flattenToString());
|
||||
|
@ -185,6 +185,11 @@ public class ActivityManager {
|
||||
* @hide
|
||||
*/
|
||||
public static final int INSTR_FLAG_ALWAYS_CHECK_SIGNATURE = 1 << 4;
|
||||
/**
|
||||
* Instrument Sdk Sandbox process that corresponds to the target package.
|
||||
* @hide
|
||||
*/
|
||||
public static final int INSTR_FLAG_INSTRUMENT_SDK_SANDBOX = 1 << 5;
|
||||
|
||||
static final class UidObserver extends IUidObserver.Stub {
|
||||
final OnUidImportanceListener mListener;
|
||||
|
@ -406,6 +406,7 @@ import com.android.server.pm.permission.PermissionManagerServiceInternal;
|
||||
import com.android.server.pm.pkg.SELinuxUtil;
|
||||
import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
|
||||
import com.android.server.pm.snapshot.PackageDataSnapshot;
|
||||
import com.android.server.sdksandbox.SdkSandboxManagerLocal;
|
||||
import com.android.server.uri.GrantUri;
|
||||
import com.android.server.uri.NeededUriGrants;
|
||||
import com.android.server.uri.UriGrantsManagerInternal;
|
||||
@ -6584,6 +6585,30 @@ public class ActivityManagerService extends IActivityManager.Stub
|
||||
final ProcessRecord addAppLocked(ApplicationInfo info, String customProcess, boolean isolated,
|
||||
boolean disableHiddenApiChecks, boolean disableTestApiChecks,
|
||||
String abiOverride, int zygotePolicyFlags) {
|
||||
return addAppLocked(
|
||||
info,
|
||||
customProcess,
|
||||
isolated,
|
||||
/* isSdkSandbox= */ false,
|
||||
/* sdkSandboxUid= */ 0,
|
||||
/* sdkSandboxClientAppPackage= */ null,
|
||||
disableHiddenApiChecks,
|
||||
disableTestApiChecks,
|
||||
abiOverride,
|
||||
zygotePolicyFlags);
|
||||
}
|
||||
|
||||
final ProcessRecord addAppLocked(
|
||||
ApplicationInfo info,
|
||||
String customProcess,
|
||||
boolean isolated,
|
||||
boolean isSdkSandbox,
|
||||
int sdkSandboxUid,
|
||||
@Nullable String sdkSandboxClientAppPackage,
|
||||
boolean disableHiddenApiChecks,
|
||||
boolean disableTestApiChecks,
|
||||
String abiOverride,
|
||||
int zygotePolicyFlags) {
|
||||
ProcessRecord app;
|
||||
if (!isolated) {
|
||||
app = getProcessRecordLocked(customProcess != null ? customProcess : info.processName,
|
||||
@ -6593,10 +6618,16 @@ public class ActivityManagerService extends IActivityManager.Stub
|
||||
}
|
||||
|
||||
if (app == null) {
|
||||
app = mProcessList.newProcessRecordLocked(info, customProcess, isolated, 0,
|
||||
false, 0, null,
|
||||
app = mProcessList.newProcessRecordLocked(
|
||||
info,
|
||||
customProcess,
|
||||
isolated,
|
||||
/* isolatedUid= */0,
|
||||
isSdkSandbox,
|
||||
sdkSandboxUid,
|
||||
sdkSandboxClientAppPackage,
|
||||
new HostingRecord("added application",
|
||||
customProcess != null ? customProcess : info.processName));
|
||||
customProcess != null ? customProcess : info.processName));
|
||||
updateLruProcessLocked(app, false, null);
|
||||
updateOomAdjLocked(app, OomAdjuster.OOM_ADJ_REASON_PROCESS_BEGIN);
|
||||
}
|
||||
@ -6606,13 +6637,16 @@ public class ActivityManagerService extends IActivityManager.Stub
|
||||
Event.APP_COMPONENT_USED);
|
||||
|
||||
// This package really, really can not be stopped.
|
||||
try {
|
||||
AppGlobals.getPackageManager().setPackageStoppedState(
|
||||
info.packageName, false, UserHandle.getUserId(app.uid));
|
||||
} catch (RemoteException e) {
|
||||
} catch (IllegalArgumentException e) {
|
||||
Slog.w(TAG, "Failed trying to unstop package "
|
||||
+ info.packageName + ": " + e);
|
||||
// TODO: how set package stopped state should work for sdk sandboxes?
|
||||
if (!isSdkSandbox) {
|
||||
try {
|
||||
AppGlobals.getPackageManager().setPackageStoppedState(
|
||||
info.packageName, false, UserHandle.getUserId(app.uid));
|
||||
} catch (RemoteException e) {
|
||||
} catch (IllegalArgumentException e) {
|
||||
Slog.w(TAG, "Failed trying to unstop package "
|
||||
+ info.packageName + ": " + e);
|
||||
}
|
||||
}
|
||||
|
||||
if ((info.flags & PERSISTENT_MASK) == PERSISTENT_MASK) {
|
||||
@ -14410,6 +14444,32 @@ public class ActivityManagerService extends IActivityManager.Stub
|
||||
}
|
||||
}
|
||||
|
||||
boolean disableHiddenApiChecks = ai.usesNonSdkApi()
|
||||
|| (flags & INSTR_FLAG_DISABLE_HIDDEN_API_CHECKS) != 0;
|
||||
boolean disableTestApiChecks = disableHiddenApiChecks
|
||||
|| (flags & INSTR_FLAG_DISABLE_TEST_API_CHECKS) != 0;
|
||||
|
||||
if (disableHiddenApiChecks || disableTestApiChecks) {
|
||||
enforceCallingPermission(android.Manifest.permission.DISABLE_HIDDEN_API_CHECKS,
|
||||
"disable hidden API checks");
|
||||
}
|
||||
|
||||
if ((flags & ActivityManager.INSTR_FLAG_INSTRUMENT_SDK_SANDBOX) != 0) {
|
||||
return startInstrumentationOfSdkSandbox(
|
||||
className,
|
||||
profileFile,
|
||||
arguments,
|
||||
watcher,
|
||||
uiAutomationConnection,
|
||||
userId,
|
||||
abiOverride,
|
||||
ii,
|
||||
ai,
|
||||
noRestart,
|
||||
disableHiddenApiChecks,
|
||||
disableTestApiChecks);
|
||||
}
|
||||
|
||||
ActiveInstrumentation activeInstr = new ActiveInstrumentation(this);
|
||||
activeInstr.mClass = className;
|
||||
String defProcess = ai.processName;;
|
||||
@ -14434,15 +14494,6 @@ public class ActivityManagerService extends IActivityManager.Stub
|
||||
START_FOREGROUND_SERVICES_FROM_BACKGROUND, callingPid, callingUid)
|
||||
== PackageManager.PERMISSION_GRANTED;
|
||||
activeInstr.mNoRestart = noRestart;
|
||||
boolean disableHiddenApiChecks = ai.usesNonSdkApi()
|
||||
|| (flags & INSTR_FLAG_DISABLE_HIDDEN_API_CHECKS) != 0;
|
||||
boolean disableTestApiChecks = disableHiddenApiChecks
|
||||
|| (flags & INSTR_FLAG_DISABLE_TEST_API_CHECKS) != 0;
|
||||
|
||||
if (disableHiddenApiChecks || disableTestApiChecks) {
|
||||
enforceCallingPermission(android.Manifest.permission.DISABLE_HIDDEN_API_CHECKS,
|
||||
"disable hidden API checks");
|
||||
}
|
||||
|
||||
final long origId = Binder.clearCallingIdentity();
|
||||
|
||||
@ -14488,6 +14539,111 @@ public class ActivityManagerService extends IActivityManager.Stub
|
||||
return true;
|
||||
}
|
||||
|
||||
@GuardedBy("this")
|
||||
private boolean startInstrumentationOfSdkSandbox(
|
||||
ComponentName className,
|
||||
String profileFile,
|
||||
Bundle arguments,
|
||||
IInstrumentationWatcher watcher,
|
||||
IUiAutomationConnection uiAutomationConnection,
|
||||
int userId,
|
||||
String abiOverride,
|
||||
InstrumentationInfo instrumentationInfo,
|
||||
ApplicationInfo sdkSandboxClientAppInfo,
|
||||
boolean noRestart,
|
||||
boolean disableHiddenApiChecks,
|
||||
boolean disableTestApiChecks) {
|
||||
|
||||
if (noRestart) {
|
||||
reportStartInstrumentationFailureLocked(
|
||||
watcher,
|
||||
className,
|
||||
"Instrumenting sdk sandbox with --no-restart flag is not supported");
|
||||
return false;
|
||||
}
|
||||
|
||||
final ApplicationInfo sdkSandboxInfo;
|
||||
try {
|
||||
final PackageManager pm = mContext.getPackageManager();
|
||||
sdkSandboxInfo = pm.getApplicationInfoAsUser(pm.getSdkSandboxPackageName(), 0, userId);
|
||||
} catch (NameNotFoundException e) {
|
||||
reportStartInstrumentationFailureLocked(
|
||||
watcher, className, "Can't find SdkSandbox package");
|
||||
return false;
|
||||
}
|
||||
|
||||
final SdkSandboxManagerLocal sandboxManagerLocal =
|
||||
LocalManagerRegistry.getManager(SdkSandboxManagerLocal.class);
|
||||
if (sandboxManagerLocal == null) {
|
||||
reportStartInstrumentationFailureLocked(
|
||||
watcher, className, "Can't locate SdkSandboxManagerLocal");
|
||||
return false;
|
||||
}
|
||||
|
||||
final String processName = sandboxManagerLocal.getSdkSandboxProcessNameForInstrumentation(
|
||||
sdkSandboxClientAppInfo);
|
||||
|
||||
ActiveInstrumentation activeInstr = new ActiveInstrumentation(this);
|
||||
activeInstr.mClass = className;
|
||||
activeInstr.mTargetProcesses = new String[]{processName};
|
||||
activeInstr.mTargetInfo = sdkSandboxInfo;
|
||||
activeInstr.mProfileFile = profileFile;
|
||||
activeInstr.mArguments = arguments;
|
||||
activeInstr.mWatcher = watcher;
|
||||
activeInstr.mUiAutomationConnection = uiAutomationConnection;
|
||||
activeInstr.mResultClass = className;
|
||||
activeInstr.mHasBackgroundActivityStartsPermission = false;
|
||||
activeInstr.mHasBackgroundForegroundServiceStartsPermission = false;
|
||||
// Instrumenting sdk sandbox without a restart is not supported
|
||||
activeInstr.mNoRestart = false;
|
||||
|
||||
final int callingUid = Binder.getCallingUid();
|
||||
final long token = Binder.clearCallingIdentity();
|
||||
try {
|
||||
sandboxManagerLocal.notifyInstrumentationStarted(
|
||||
sdkSandboxClientAppInfo.packageName, sdkSandboxClientAppInfo.uid);
|
||||
synchronized (mProcLock) {
|
||||
int sdkSandboxUid = Process.toSdkSandboxUid(sdkSandboxClientAppInfo.uid);
|
||||
// Kill the package sdk sandbox process belong to. At this point sdk sandbox is
|
||||
// already killed.
|
||||
forceStopPackageLocked(
|
||||
instrumentationInfo.targetPackage,
|
||||
/* appId= */ -1,
|
||||
/* callerWillRestart= */ true,
|
||||
/* purgeCache= */ false,
|
||||
/* doIt= */ true,
|
||||
/* evenPersistent= */ true,
|
||||
/* uninstalling= */ false,
|
||||
userId,
|
||||
"start instr");
|
||||
|
||||
ProcessRecord app = addAppLocked(
|
||||
sdkSandboxInfo,
|
||||
processName,
|
||||
/* isolated= */ false,
|
||||
/* isSdkSandbox= */ true,
|
||||
sdkSandboxUid,
|
||||
sdkSandboxClientAppInfo.packageName,
|
||||
disableHiddenApiChecks,
|
||||
disableTestApiChecks,
|
||||
abiOverride,
|
||||
ZYGOTE_POLICY_FLAG_EMPTY);
|
||||
|
||||
app.setActiveInstrumentation(activeInstr);
|
||||
activeInstr.mFinished = false;
|
||||
activeInstr.mSourceUid = callingUid;
|
||||
activeInstr.mRunningProcesses.add(app);
|
||||
if (!mActiveInstrumentation.contains(activeInstr)) {
|
||||
mActiveInstrumentation.add(activeInstr);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(token);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void instrumentWithoutRestart(ActiveInstrumentation activeInstr,
|
||||
ApplicationInfo targetInfo) {
|
||||
ProcessRecord pr;
|
||||
@ -14610,7 +14766,17 @@ public class ActivityManagerService extends IActivityManager.Stub
|
||||
app.setActiveInstrumentation(null);
|
||||
}
|
||||
|
||||
if (!instr.mNoRestart) {
|
||||
if (app.isSdkSandbox) {
|
||||
// For sharedUid apps this will kill all sdk sandbox processes, which is not ideal.
|
||||
// TODO(b/209061624): should we call ProcessList.removeProcessLocked instead?
|
||||
killUid(UserHandle.getAppId(app.uid), UserHandle.getUserId(app.uid), "finished instr");
|
||||
final SdkSandboxManagerLocal sandboxManagerLocal =
|
||||
LocalManagerRegistry.getManager(SdkSandboxManagerLocal.class);
|
||||
if (sandboxManagerLocal != null) {
|
||||
sandboxManagerLocal.notifyInstrumentationFinished(
|
||||
app.sdkSandboxClientAppPackage, Process.getAppUidForSdkSandboxUid(app.uid));
|
||||
}
|
||||
} else if (!instr.mNoRestart) {
|
||||
forceStopPackageLocked(app.info.packageName, -1, false, false, true, true, false,
|
||||
app.userId,
|
||||
"finished inst");
|
||||
|
Loading…
x
Reference in New Issue
Block a user