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;
|
instrument.noRestart = true;
|
||||||
} else if (opt.equals("--always-check-signature")) {
|
} else if (opt.equals("--always-check-signature")) {
|
||||||
instrument.alwaysCheckSignature = true;
|
instrument.alwaysCheckSignature = true;
|
||||||
|
} else if (opt.equals("--instrument-sdk-sandbox")) {
|
||||||
|
instrument.instrumentSdkSandbox = true;
|
||||||
} else {
|
} else {
|
||||||
System.err.println("Error: Unknown option: " + opt);
|
System.err.println("Error: Unknown option: " + opt);
|
||||||
return;
|
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_HIDDEN_API_CHECKS;
|
||||||
import static android.app.ActivityManager.INSTR_FLAG_DISABLE_ISOLATED_STORAGE;
|
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_DISABLE_TEST_API_CHECKS;
|
||||||
|
import static android.app.ActivityManager.INSTR_FLAG_INSTRUMENT_SDK_SANDBOX;
|
||||||
import static android.app.ActivityManager.INSTR_FLAG_NO_RESTART;
|
import static android.app.ActivityManager.INSTR_FLAG_NO_RESTART;
|
||||||
|
|
||||||
import android.app.IActivityManager;
|
import android.app.IActivityManager;
|
||||||
@ -97,6 +98,7 @@ public class Instrument {
|
|||||||
// Required
|
// Required
|
||||||
public String componentNameArg;
|
public String componentNameArg;
|
||||||
public boolean alwaysCheckSignature = false;
|
public boolean alwaysCheckSignature = false;
|
||||||
|
public boolean instrumentSdkSandbox = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct the instrument command runner.
|
* Construct the instrument command runner.
|
||||||
@ -524,6 +526,9 @@ public class Instrument {
|
|||||||
if (alwaysCheckSignature) {
|
if (alwaysCheckSignature) {
|
||||||
flags |= INSTR_FLAG_ALWAYS_CHECK_SIGNATURE;
|
flags |= INSTR_FLAG_ALWAYS_CHECK_SIGNATURE;
|
||||||
}
|
}
|
||||||
|
if (instrumentSdkSandbox) {
|
||||||
|
flags |= INSTR_FLAG_INSTRUMENT_SDK_SANDBOX;
|
||||||
|
}
|
||||||
if (!mAm.startInstrumentation(cn, profileFile, flags, args, watcher, connection, userId,
|
if (!mAm.startInstrumentation(cn, profileFile, flags, args, watcher, connection, userId,
|
||||||
abi)) {
|
abi)) {
|
||||||
throw new AndroidException("INSTRUMENTATION_FAILED: " + cn.flattenToString());
|
throw new AndroidException("INSTRUMENTATION_FAILED: " + cn.flattenToString());
|
||||||
|
@ -185,6 +185,11 @@ public class ActivityManager {
|
|||||||
* @hide
|
* @hide
|
||||||
*/
|
*/
|
||||||
public static final int INSTR_FLAG_ALWAYS_CHECK_SIGNATURE = 1 << 4;
|
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 {
|
static final class UidObserver extends IUidObserver.Stub {
|
||||||
final OnUidImportanceListener mListener;
|
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.SELinuxUtil;
|
||||||
import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
|
import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
|
||||||
import com.android.server.pm.snapshot.PackageDataSnapshot;
|
import com.android.server.pm.snapshot.PackageDataSnapshot;
|
||||||
|
import com.android.server.sdksandbox.SdkSandboxManagerLocal;
|
||||||
import com.android.server.uri.GrantUri;
|
import com.android.server.uri.GrantUri;
|
||||||
import com.android.server.uri.NeededUriGrants;
|
import com.android.server.uri.NeededUriGrants;
|
||||||
import com.android.server.uri.UriGrantsManagerInternal;
|
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,
|
final ProcessRecord addAppLocked(ApplicationInfo info, String customProcess, boolean isolated,
|
||||||
boolean disableHiddenApiChecks, boolean disableTestApiChecks,
|
boolean disableHiddenApiChecks, boolean disableTestApiChecks,
|
||||||
String abiOverride, int zygotePolicyFlags) {
|
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;
|
ProcessRecord app;
|
||||||
if (!isolated) {
|
if (!isolated) {
|
||||||
app = getProcessRecordLocked(customProcess != null ? customProcess : info.processName,
|
app = getProcessRecordLocked(customProcess != null ? customProcess : info.processName,
|
||||||
@ -6593,10 +6618,16 @@ public class ActivityManagerService extends IActivityManager.Stub
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (app == null) {
|
if (app == null) {
|
||||||
app = mProcessList.newProcessRecordLocked(info, customProcess, isolated, 0,
|
app = mProcessList.newProcessRecordLocked(
|
||||||
false, 0, null,
|
info,
|
||||||
|
customProcess,
|
||||||
|
isolated,
|
||||||
|
/* isolatedUid= */0,
|
||||||
|
isSdkSandbox,
|
||||||
|
sdkSandboxUid,
|
||||||
|
sdkSandboxClientAppPackage,
|
||||||
new HostingRecord("added application",
|
new HostingRecord("added application",
|
||||||
customProcess != null ? customProcess : info.processName));
|
customProcess != null ? customProcess : info.processName));
|
||||||
updateLruProcessLocked(app, false, null);
|
updateLruProcessLocked(app, false, null);
|
||||||
updateOomAdjLocked(app, OomAdjuster.OOM_ADJ_REASON_PROCESS_BEGIN);
|
updateOomAdjLocked(app, OomAdjuster.OOM_ADJ_REASON_PROCESS_BEGIN);
|
||||||
}
|
}
|
||||||
@ -6606,13 +6637,16 @@ public class ActivityManagerService extends IActivityManager.Stub
|
|||||||
Event.APP_COMPONENT_USED);
|
Event.APP_COMPONENT_USED);
|
||||||
|
|
||||||
// This package really, really can not be stopped.
|
// This package really, really can not be stopped.
|
||||||
try {
|
// TODO: how set package stopped state should work for sdk sandboxes?
|
||||||
AppGlobals.getPackageManager().setPackageStoppedState(
|
if (!isSdkSandbox) {
|
||||||
info.packageName, false, UserHandle.getUserId(app.uid));
|
try {
|
||||||
} catch (RemoteException e) {
|
AppGlobals.getPackageManager().setPackageStoppedState(
|
||||||
} catch (IllegalArgumentException e) {
|
info.packageName, false, UserHandle.getUserId(app.uid));
|
||||||
Slog.w(TAG, "Failed trying to unstop package "
|
} catch (RemoteException e) {
|
||||||
+ info.packageName + ": " + e);
|
} catch (IllegalArgumentException e) {
|
||||||
|
Slog.w(TAG, "Failed trying to unstop package "
|
||||||
|
+ info.packageName + ": " + e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((info.flags & PERSISTENT_MASK) == PERSISTENT_MASK) {
|
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);
|
ActiveInstrumentation activeInstr = new ActiveInstrumentation(this);
|
||||||
activeInstr.mClass = className;
|
activeInstr.mClass = className;
|
||||||
String defProcess = ai.processName;;
|
String defProcess = ai.processName;;
|
||||||
@ -14434,15 +14494,6 @@ public class ActivityManagerService extends IActivityManager.Stub
|
|||||||
START_FOREGROUND_SERVICES_FROM_BACKGROUND, callingPid, callingUid)
|
START_FOREGROUND_SERVICES_FROM_BACKGROUND, callingPid, callingUid)
|
||||||
== PackageManager.PERMISSION_GRANTED;
|
== PackageManager.PERMISSION_GRANTED;
|
||||||
activeInstr.mNoRestart = noRestart;
|
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();
|
final long origId = Binder.clearCallingIdentity();
|
||||||
|
|
||||||
@ -14488,6 +14539,111 @@ public class ActivityManagerService extends IActivityManager.Stub
|
|||||||
return true;
|
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,
|
private void instrumentWithoutRestart(ActiveInstrumentation activeInstr,
|
||||||
ApplicationInfo targetInfo) {
|
ApplicationInfo targetInfo) {
|
||||||
ProcessRecord pr;
|
ProcessRecord pr;
|
||||||
@ -14610,7 +14766,17 @@ public class ActivityManagerService extends IActivityManager.Stub
|
|||||||
app.setActiveInstrumentation(null);
|
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,
|
forceStopPackageLocked(app.info.packageName, -1, false, false, true, true, false,
|
||||||
app.userId,
|
app.userId,
|
||||||
"finished inst");
|
"finished inst");
|
||||||
|
Loading…
x
Reference in New Issue
Block a user