Moved input time out handling to ActivityTaskManagerService (14/n)
Also:
- Post handling of scheduling GC from WM to AM side.
- Removed access on package manager through mAm reference.
Bug: 80414790
Test: Existing tests pass
Change-Id: Ia76c57411fc332ea099adb6ef7975e012b4d744c
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 29937ab..5bf6892 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -3658,7 +3658,7 @@
}
app = r.app;
- if (app != null && app.debugging) {
+ if (app != null && app.isDebugging()) {
// The app's being debugged; let it ride
return;
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 594b391..8b25605 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -463,12 +463,6 @@
static final int BROADCAST_FG_TIMEOUT = 10*1000;
static final int BROADCAST_BG_TIMEOUT = 60*1000;
- // How long we wait until we timeout on key dispatching.
- static final int KEY_DISPATCHING_TIMEOUT = 5*1000;
-
- // How long we wait until we timeout on key dispatching during instrumentation.
- static final int INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT = 60*1000;
-
// Disable hidden API checks for the newly started instrumentation.
// Must be kept in sync with Am.
private static final int INSTRUMENTATION_FLAG_DISABLE_HIDDEN_API_CHECKS = 1 << 0;
@@ -695,10 +689,42 @@
* All of the processes we currently have running organized by pid.
* The keys are the pid running the application.
*
- * <p>NOTE: This object is protected by its own lock, NOT the global
- * activity manager lock!
+ * <p>NOTE: This object is protected by its own lock, NOT the global activity manager lock!
*/
- final SparseArray<ProcessRecord> mPidsSelfLocked = new SparseArray<ProcessRecord>();
+ final PidMap mPidsSelfLocked = new PidMap();
+ final class PidMap {
+ private final SparseArray<ProcessRecord> mPidMap = new SparseArray<>();
+
+ void put(int key, ProcessRecord value) {
+ mPidMap.put(key, value);
+ mAtmInternal.onProcessMapped(key, value.getWindowProcessController());
+ }
+
+ void remove(int pid) {
+ mPidMap.remove(pid);
+ mAtmInternal.onProcessUnMapped(pid);
+ }
+
+ ProcessRecord get(int pid) {
+ return mPidMap.get(pid);
+ }
+
+ int size() {
+ return mPidMap.size();
+ }
+
+ ProcessRecord valueAt(int index) {
+ return mPidMap.valueAt(index);
+ }
+
+ int keyAt(int index) {
+ return mPidMap.keyAt(index);
+ }
+
+ int indexOfKey(int key) {
+ return mPidMap.indexOfKey(key);
+ }
+ }
/**
* All of the processes that have been forced to be important. The key
@@ -3635,8 +3661,8 @@
app.pendingStart = false;
return;
}
- app.usingWrapper = invokeWith != null
- || SystemProperties.get("wrap." + app.processName) != null;
+ app.setUsingWrapper(invokeWith != null
+ || SystemProperties.get("wrap." + app.processName) != null);
mPendingStarts.put(startSeq, app);
}
final ProcessStartResult startResult = startProcess(app.hostingType, entryPoint,
@@ -3732,7 +3758,7 @@
// Indicates that this process start has been taken care of.
if (mPendingStarts.get(expectedStartSeq) == null) {
if (pending.pid == startResult.pid) {
- pending.usingWrapper = startResult.usingWrapper;
+ pending.setUsingWrapper(startResult.usingWrapper);
// TODO: Update already existing clients of usingWrapper
}
return false;
@@ -3795,7 +3821,7 @@
}
reportUidInfoMessageLocked(TAG, buf.toString(), app.startUid);
app.setPid(pid);
- app.usingWrapper = usingWrapper;
+ app.setUsingWrapper(usingWrapper);
app.pendingStart = false;
checkTime(app.startTime, "startProcess: starting to update pids map");
ProcessRecord oldApp;
@@ -3880,7 +3906,7 @@
aInfo.applicationInfo = getAppInfoForUser(aInfo.applicationInfo, userId);
ProcessRecord app = getProcessRecordLocked(aInfo.processName,
aInfo.applicationInfo.uid, true);
- if (app == null || app.instr == null) {
+ if (app == null || app.getActiveInstrumentation() == null) {
intent.setFlags(intent.getFlags() | FLAG_ACTIVITY_NEW_TASK);
final int resolvedUserId = UserHandle.getUserId(aInfo.applicationInfo.uid);
// For ANR debugging to verify if the user activity is the one that actually
@@ -4400,9 +4426,9 @@
app.clearRecentTasks();
app.clearActivities();
- if (app.instr != null) {
+ if (app.getActiveInstrumentation() != null) {
Slog.w(TAG, "Crash of app " + app.processName
- + " running instrumentation " + app.instr.mClass);
+ + " running instrumentation " + app.getActiveInstrumentation().mClass);
Bundle info = new Bundle();
info.putString("shortMsg", "Process crashed.");
finishInstrumentationLocked(app, Activity.RESULT_CANCELED, info);
@@ -4556,7 +4582,7 @@
// Clean up already done if the process has been re-started.
if (app.pid == pid && app.thread != null &&
app.thread.asBinder() == thread.asBinder()) {
- boolean doLowMem = app.instr == null;
+ boolean doLowMem = app.getActiveInstrumentation() == null;
boolean doOomAdj = doLowMem;
if (!app.killedByAm) {
reportUidInfoMessageLocked(TAG,
@@ -5885,7 +5911,7 @@
if (app == null && startSeq > 0) {
final ProcessRecord pending = mPendingStarts.get(startSeq);
if (pending != null && pending.startUid == callingUid
- && handleProcessStartedLocked(pending, pid, pending.usingWrapper,
+ && handleProcessStartedLocked(pending, pid, pending.isUsingWrapper(),
startSeq, true)) {
app = pending;
}
@@ -5939,7 +5965,7 @@
app.forcingToImportant = null;
updateProcessForegroundLocked(app, false, false);
app.hasShownUi = false;
- app.debugging = false;
+ app.setDebugging(false);
app.cached = false;
app.killedByAm = false;
app.killed = false;
@@ -5976,7 +6002,7 @@
testMode = mWaitForDebugger
? ApplicationThreadConstants.DEBUG_WAIT
: ApplicationThreadConstants.DEBUG_ON;
- app.debugging = true;
+ app.setDebugging(true);
if (mDebugTransient) {
mDebugApp = mOrigDebugApp;
mWaitForDebugger = mOrigWaitForDebugger;
@@ -5998,13 +6024,15 @@
|| (mBackupTarget.backupMode == BackupRecord.BACKUP_FULL));
}
- if (app.instr != null) {
- notifyPackageUse(app.instr.mClass.getPackageName(),
+ final ActiveInstrumentation instr = app.getActiveInstrumentation();
+
+ if (instr != null) {
+ notifyPackageUse(instr.mClass.getPackageName(),
PackageManager.NOTIFY_PACKAGE_USE_INSTRUMENTATION);
}
if (DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, "Binding proc "
+ processName + " with config " + getGlobalConfiguration());
- ApplicationInfo appInfo = app.instr != null ? app.instr.mTargetInfo : app.info;
+ ApplicationInfo appInfo = instr != null ? instr.mTargetInfo : app.info;
app.compat = compatibilityInfoForPackageLocked(appInfo);
ProfilerInfo profilerInfo = null;
@@ -6021,8 +6049,8 @@
preBindAgent = mProfilerInfo.agent;
}
}
- } else if (app.instr != null && app.instr.mProfileFile != null) {
- profilerInfo = new ProfilerInfo(app.instr.mProfileFile, null, 0, false, false,
+ } else if (instr != null && instr.mProfileFile != null) {
+ profilerInfo = new ProfilerInfo(instr.mProfileFile, null, 0, false, false,
null, false);
}
if (mAppAgentMap != null && mAppAgentMap.containsKey(processName)) {
@@ -6059,21 +6087,22 @@
// currently active instrumentation. (Note we do this AFTER all of the profiling
// stuff above because profiling can currently happen only in the primary
// instrumentation process.)
- if (mActiveInstrumentation.size() > 0 && app.instr == null) {
- for (int i = mActiveInstrumentation.size() - 1; i >= 0 && app.instr == null; i--) {
+ if (mActiveInstrumentation.size() > 0 && instr == null) {
+ for (int i = mActiveInstrumentation.size() - 1;
+ i >= 0 && app.getActiveInstrumentation() == null; i--) {
ActiveInstrumentation aInstr = mActiveInstrumentation.get(i);
if (!aInstr.mFinished && aInstr.mTargetInfo.uid == app.uid) {
if (aInstr.mTargetProcesses.length == 0) {
// This is the wildcard mode, where every process brought up for
// the target instrumentation should be included.
if (aInstr.mTargetInfo.packageName.equals(app.info.packageName)) {
- app.instr = aInstr;
+ app.setActiveInstrumentation(aInstr);
aInstr.mRunningProcesses.add(app);
}
} else {
for (String proc : aInstr.mTargetProcesses) {
if (proc.equals(app.processName)) {
- app.instr = aInstr;
+ app.setActiveInstrumentation(aInstr);
aInstr.mRunningProcesses.add(app);
break;
}
@@ -6103,16 +6132,17 @@
checkTime(startTime, "attachApplicationLocked: immediately before bindApplication");
mStackSupervisor.getActivityMetricsLogger().notifyBindApplication(app);
+ final ActiveInstrumentation instr2 = app.getActiveInstrumentation();
if (app.isolatedEntryPoint != null) {
// This is an isolated process which should just call an entry point instead of
// being bound to an application.
thread.runIsolatedEntryPoint(app.isolatedEntryPoint, app.isolatedEntryPointArgs);
- } else if (app.instr != null) {
+ } else if (instr2 != null) {
thread.bindApplication(processName, appInfo, providers,
- app.instr.mClass,
- profilerInfo, app.instr.mArguments,
- app.instr.mWatcher,
- app.instr.mUiAutomationConnection, testMode,
+ instr2.mClass,
+ profilerInfo, instr2.mArguments,
+ instr2.mWatcher,
+ instr2.mUiAutomationConnection, testMode,
mBinderTransactionTrackingEnabled, enableTrackAllocation,
isRestrictedBackupMode || !normalMode, app.isPersistent(),
new Configuration(getGlobalConfiguration()), app.compat,
@@ -9257,7 +9287,8 @@
if (proc == null) {
throw new SecurityException("Unknown process: " + callingPid);
}
- if (proc.instr == null || proc.instr.mUiAutomationConnection == null) {
+ if (proc.getActiveInstrumentation() == null
+ || proc.getActiveInstrumentation().mUiAutomationConnection == null) {
throw new SecurityException("Only an instrumentation process "
+ "with a UiAutomation can call setUserIsMonkey");
}
@@ -9380,89 +9411,6 @@
ActivityManager.BUGREPORT_OPTION_WIFI);
}
-
- public static long getInputDispatchingTimeoutLocked(ActivityRecord r) {
- if (r == null || !r.hasProcess()) {
- return KEY_DISPATCHING_TIMEOUT;
- }
- return getInputDispatchingTimeoutLocked((ProcessRecord) r.app.mOwner);
- }
-
- public static long getInputDispatchingTimeoutLocked(ProcessRecord r) {
- if (r != null && (r.instr != null || r.usingWrapper)) {
- return INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT;
- }
- return KEY_DISPATCHING_TIMEOUT;
- }
-
- @Override
- public long inputDispatchingTimedOut(int pid, final boolean aboveSystem, String reason) {
- if (checkCallingPermission(android.Manifest.permission.FILTER_EVENTS)
- != PackageManager.PERMISSION_GRANTED) {
- throw new SecurityException("Requires permission "
- + android.Manifest.permission.FILTER_EVENTS);
- }
- ProcessRecord proc;
- long timeout;
- synchronized (this) {
- synchronized (mPidsSelfLocked) {
- proc = mPidsSelfLocked.get(pid);
- }
- timeout = getInputDispatchingTimeoutLocked(proc);
- }
-
- if (inputDispatchingTimedOut(proc, null, null, aboveSystem, reason)) {
- return -1;
- }
-
- return timeout;
- }
-
- /**
- * Handle input dispatching timeouts.
- * Returns whether input dispatching should be aborted or not.
- */
- public boolean inputDispatchingTimedOut(final ProcessRecord proc,
- final ActivityRecord activity, final ActivityRecord parent,
- final boolean aboveSystem, String reason) {
- if (checkCallingPermission(android.Manifest.permission.FILTER_EVENTS)
- != PackageManager.PERMISSION_GRANTED) {
- throw new SecurityException("Requires permission "
- + android.Manifest.permission.FILTER_EVENTS);
- }
-
- final String annotation;
- if (reason == null) {
- annotation = "Input dispatching timed out";
- } else {
- annotation = "Input dispatching timed out (" + reason + ")";
- }
-
- if (proc != null) {
- synchronized (this) {
- if (proc.debugging) {
- return false;
- }
-
- if (proc.instr != null) {
- Bundle info = new Bundle();
- info.putString("shortMsg", "keyDispatchingTimedOut");
- info.putString("longMsg", annotation);
- finishInstrumentationLocked(proc, Activity.RESULT_CANCELED, info);
- return true;
- }
- }
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- mAppErrors.appNotResponding(proc, activity, parent, aboveSystem, annotation);
- }
- });
- }
-
- return true;
- }
-
public void registerProcessObserver(IProcessObserver observer) {
enforceCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER,
"registerProcessObserver()");
@@ -17137,7 +17085,7 @@
ProcessRecord app = addAppLocked(ai, defProcess, false, disableHiddenApiChecks,
abiOverride);
- app.instr = activeInstr;
+ app.setActiveInstrumentation(activeInstr);
activeInstr.mFinished = false;
activeInstr.mRunningProcesses.add(app);
if (!mActiveInstrumentation.contains(activeInstr)) {
@@ -17170,16 +17118,17 @@
}
void addInstrumentationResultsLocked(ProcessRecord app, Bundle results) {
- if (app.instr == null) {
+ final ActiveInstrumentation instr = app.getActiveInstrumentation();
+ if (instr == null) {
Slog.w(TAG, "finishInstrumentation called on non-instrumented: " + app);
return;
}
- if (!app.instr.mFinished && results != null) {
- if (app.instr.mCurResults == null) {
- app.instr.mCurResults = new Bundle(results);
+ if (!instr.mFinished && results != null) {
+ if (instr.mCurResults == null) {
+ instr.mCurResults = new Bundle(results);
} else {
- app.instr.mCurResults.putAll(results);
+ instr.mCurResults.putAll(results);
}
}
}
@@ -17205,37 +17154,38 @@
@GuardedBy("this")
void finishInstrumentationLocked(ProcessRecord app, int resultCode, Bundle results) {
- if (app.instr == null) {
+ final ActiveInstrumentation instr = app.getActiveInstrumentation();
+ if (instr == null) {
Slog.w(TAG, "finishInstrumentation called on non-instrumented: " + app);
return;
}
- if (!app.instr.mFinished) {
- if (app.instr.mWatcher != null) {
- Bundle finalResults = app.instr.mCurResults;
+ if (!instr.mFinished) {
+ if (instr.mWatcher != null) {
+ Bundle finalResults = instr.mCurResults;
if (finalResults != null) {
- if (app.instr.mCurResults != null && results != null) {
+ if (instr.mCurResults != null && results != null) {
finalResults.putAll(results);
}
} else {
finalResults = results;
}
- mInstrumentationReporter.reportFinished(app.instr.mWatcher,
- app.instr.mClass, resultCode, finalResults);
+ mInstrumentationReporter.reportFinished(instr.mWatcher,
+ instr.mClass, resultCode, finalResults);
}
// Can't call out of the system process with a lock held, so post a message.
- if (app.instr.mUiAutomationConnection != null) {
+ if (instr.mUiAutomationConnection != null) {
mAppOpsService.setAppOpsServiceDelegate(null);
getPackageManagerInternalLocked().setCheckPermissionDelegate(null);
mHandler.obtainMessage(SHUTDOWN_UI_AUTOMATION_CONNECTION_MSG,
- app.instr.mUiAutomationConnection).sendToTarget();
+ instr.mUiAutomationConnection).sendToTarget();
}
- app.instr.mFinished = true;
+ instr.mFinished = true;
}
- app.instr.removeProcess(app);
- app.instr = null;
+ instr.removeProcess(app);
+ app.setActiveInstrumentation(null);
forceStopPackageLocked(app.info.packageName, -1, false, false, true, true, false, app.userId,
"finished inst");
@@ -17709,7 +17659,7 @@
if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
reportOomAdjMessageLocked(TAG_OOM_ADJ, "Making running remote anim: " + app);
}
- } else if (app.instr != null) {
+ } else if (app.getActiveInstrumentation() != null) {
// Don't want to kill running instrumentation.
adj = ProcessList.FOREGROUND_APP_ADJ;
schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
@@ -21208,6 +21158,13 @@
return ActivityManagerService.this.getHomeIntent();
}
}
+
+ @Override
+ public void scheduleAppGcs() {
+ synchronized (ActivityManagerService.this) {
+ ActivityManagerService.this.scheduleAppGcsLocked();
+ }
+ }
}
/**
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 19ea955..c9f239e 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -1036,7 +1036,7 @@
(info.flags & FLAG_SHOW_FOR_ALL_USERS) != 0, info.configChanges,
task.voiceSession != null, mLaunchTaskBehind, isAlwaysFocusable(),
appInfo.targetSdkVersion, mRotationAnimationHint,
- ActivityManagerService.getInputDispatchingTimeoutLocked(this) * 1000000L);
+ ActivityTaskManagerService.getInputDispatchingTimeoutLocked(this) * 1000000L);
task.addActivityToTop(this);
@@ -2134,7 +2134,7 @@
mStackSupervisor.processStoppingActivitiesLocked(null /* idleActivity */,
false /* remove */, true /* processPausingActivities */);
}
- service.mAm.scheduleAppGcsLocked();
+ service.scheduleAppGcsLocked();
}
}
}
@@ -2159,13 +2159,11 @@
!hasProcess() || app.getPid() == windowPid || windowPid == -1;
}
if (windowFromSameProcessAsActivity) {
- return service.mAm.inputDispatchingTimedOut(
- (ProcessRecord) anrApp.mOwner, anrActivity, this, false, reason);
+ return service.inputDispatchingTimedOut(anrApp, anrActivity, this, false, reason);
} else {
// In this case another process added windows using this activity token. So, we call the
// generic service input dispatch timed out method so that the right process is blamed.
- return service.mAm.inputDispatchingTimedOut(
- windowPid, false /* aboveSystem */, reason) < 0;
+ return service.inputDispatchingTimedOut(windowPid, false /* aboveSystem */, reason) < 0;
}
}
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index a732575..70ac197 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -1400,7 +1400,7 @@
// (e.g. AMS.startActivityAsUser).
final long token = Binder.clearCallingIdentity();
try {
- return mService.mAm.getPackageManagerInternalLocked().resolveIntent(
+ return mService.getPackageManagerInternalLocked().resolveIntent(
intent, resolvedType, modifiedFlags, userId, true, filterCallingUid);
} finally {
Binder.restoreCallingIdentity(token);
@@ -2109,7 +2109,7 @@
if (allResumedActivitiesIdle()) {
if (r != null) {
- mService.mAm.scheduleAppGcsLocked();
+ mService.scheduleAppGcsLocked();
}
if (mLaunchingActivity.isHeld()) {
diff --git a/services/core/java/com/android/server/am/ActivityStartInterceptor.java b/services/core/java/com/android/server/am/ActivityStartInterceptor.java
index ca12716..177e2f5 100644
--- a/services/core/java/com/android/server/am/ActivityStartInterceptor.java
+++ b/services/core/java/com/android/server/am/ActivityStartInterceptor.java
@@ -237,7 +237,7 @@
(mAInfo.applicationInfo.flags & FLAG_SUSPENDED) == 0) {
return false;
}
- final PackageManagerInternal pmi = mService.mAm.getPackageManagerInternalLocked();
+ final PackageManagerInternal pmi = mService.getPackageManagerInternalLocked();
if (pmi == null) {
return false;
}
@@ -318,7 +318,7 @@
private boolean interceptHarmfulAppIfNeeded() {
CharSequence harmfulAppWarning;
try {
- harmfulAppWarning = mService.mAm.getPackageManager()
+ harmfulAppWarning = mService.getPackageManager()
.getHarmfulAppWarning(mAInfo.packageName, mUserId);
} catch (RemoteException ex) {
return false;
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index 8be5ada..0a1b26c 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -672,7 +672,7 @@
&& sourceRecord.info.applicationInfo.uid != aInfo.applicationInfo.uid) {
try {
intent.addCategory(Intent.CATEGORY_VOICE);
- if (!mService.mAm.getPackageManager().activitySupportsIntent(
+ if (!mService.getPackageManager().activitySupportsIntent(
intent.getComponent(), intent, resolvedType)) {
Slog.w(TAG,
"Activity being started in current voice task does not support voice: "
@@ -690,7 +690,7 @@
// If the caller is starting a new voice session, just make sure the target
// is actually allowing it to run this way.
try {
- if (!mService.mAm.getPackageManager().activitySupportsIntent(intent.getComponent(),
+ if (!mService.getPackageManager().activitySupportsIntent(intent.getComponent(),
intent, resolvedType)) {
Slog.w(TAG,
"Activity being started in new voice task does not support: "
@@ -772,7 +772,7 @@
// launch the review activity and pass a pending intent to start the activity
// we are to launching now after the review is completed.
if (aInfo != null) {
- if (mService.mAm.getPackageManagerInternalLocked().isPermissionsReviewRequired(
+ if (mService.getPackageManagerInternalLocked().isPermissionsReviewRequired(
aInfo.packageName, userId)) {
IIntentSender target = mService.mAm.getIntentSenderLocked(
ActivityManager.INTENT_SENDER_ACTIVITY, callingPackage,
@@ -870,7 +870,7 @@
String resolvedType, int userId) {
if (auxiliaryResponse != null && auxiliaryResponse.needsPhaseTwo) {
// request phase two resolution
- mService.mAm.getPackageManagerInternalLocked().requestInstantAppResolutionPhaseTwo(
+ mService.getPackageManagerInternalLocked().requestInstantAppResolutionPhaseTwo(
auxiliaryResponse, originalIntent, resolvedType, callingPackage,
verificationBundle, userId);
}
@@ -970,7 +970,7 @@
&& !(Intent.ACTION_VIEW.equals(intent.getAction()) && intent.getData() == null)
&& !Intent.ACTION_INSTALL_INSTANT_APP_PACKAGE.equals(intent.getAction())
&& !Intent.ACTION_RESOLVE_INSTANT_APP_PACKAGE.equals(intent.getAction())
- && mService.mAm.getPackageManagerInternalLocked()
+ && mService.getPackageManagerInternalLocked()
.isInstantAppInstallerComponent(intent.getComponent())) {
// intercept intents targeted directly to the ephemeral installer the
// ephemeral installer should never be started with a raw Intent; instead
diff --git a/services/core/java/com/android/server/am/ActivityTaskManagerService.java b/services/core/java/com/android/server/am/ActivityTaskManagerService.java
index ab1ba6c..4a0f692 100644
--- a/services/core/java/com/android/server/am/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityTaskManagerService.java
@@ -19,6 +19,7 @@
import static android.Manifest.permission.BIND_VOICE_INTERACTION;
import static android.Manifest.permission.CHANGE_CONFIGURATION;
import static android.Manifest.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS;
+import static android.Manifest.permission.FILTER_EVENTS;
import static android.Manifest.permission.INTERNAL_SYSTEM_WINDOW;
import static android.Manifest.permission.MANAGE_ACTIVITY_STACKS;
import static android.Manifest.permission.READ_FRAME_BUFFER;
@@ -36,15 +37,12 @@
import static com.android.server.wm.ActivityTaskManagerInternal.ASSIST_KEY_DATA;
import static com.android.server.wm.ActivityTaskManagerInternal.ASSIST_KEY_RECEIVER_EXTRAS;
import static com.android.server.wm.ActivityTaskManagerInternal.ASSIST_KEY_STRUCTURE;
-import static android.app.ActivityTaskManager.INVALID_STACK_ID;
import static android.app.ActivityTaskManager.RESIZE_MODE_PRESERVE_WINDOW;
import static android.app.ActivityTaskManager.SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT;
import static android.app.AppOpsManager.OP_NONE;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
-import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
@@ -74,7 +72,6 @@
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_FOCUS;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_IMMERSIVE;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_LOCKTASK;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_OOM_ADJ;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_STACK;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SWITCH;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_TASKS;
@@ -122,6 +119,8 @@
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.DialogInterface;
+import android.content.pm.IPackageManager;
+import android.content.pm.PackageManagerInternal;
import android.database.ContentObserver;
import android.os.IUserManager;
import android.os.PowerManager;
@@ -131,7 +130,6 @@
import android.os.WorkSource;
import android.view.WindowManager;
import com.android.internal.R;
-import com.android.internal.annotations.GuardedBy;
import com.android.internal.app.IAppOpsService;
import com.android.server.AppOpsService;
import com.android.server.pm.UserManagerService;
@@ -181,7 +179,6 @@
import android.os.Looper;
import android.os.Message;
import android.os.PersistableBundle;
-import android.os.Process;
import android.os.RemoteException;
import android.os.StrictMode;
import android.os.SystemClock;
@@ -250,6 +247,11 @@
private static final String TAG_LOCKTASK = TAG + POSTFIX_LOCKTASK;
private static final String TAG_CONFIGURATION = TAG + POSTFIX_CONFIGURATION;
+ // How long we wait until we timeout on key dispatching.
+ private static final int KEY_DISPATCHING_TIMEOUT_MS = 5 * 1000;
+ // How long we wait until we timeout on key dispatching during instrumentation.
+ private static final int INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT_MS = 60 * 1000;
+
Context mContext;
/**
* This Context is themable and meant for UI display (AlertDialogs, etc.). The theme can
@@ -261,6 +263,7 @@
ActivityManagerService mAm;
ActivityManagerInternal mAmInternal;
UriGrantsManagerInternal mUgmInternal;
+ private PackageManagerInternal mPmInternal;
/* Global service lock used by the package the owns this service. */
Object mGlobalLock;
ActivityStackSupervisor mStackSupervisor;
@@ -269,6 +272,8 @@
private AppOpsService mAppOpsService;
/** All processes currently running that might have a window organized by name. */
final ProcessMap<WindowProcessController> mProcessNames = new ProcessMap<>();
+ /** All processes we currently have running mapped by pid */
+ final SparseArray<WindowProcessController> mPidMap = new SparseArray<>();
/** This is the process holding what we currently consider to be the "home" activity. */
WindowProcessController mHomeProcess;
/**
@@ -4540,6 +4545,80 @@
&& mAmInternal.getCurrentUser().isDemo());
}
+ static long getInputDispatchingTimeoutLocked(ActivityRecord r) {
+ if (r == null || !r.hasProcess()) {
+ return KEY_DISPATCHING_TIMEOUT_MS;
+ }
+ return getInputDispatchingTimeoutLocked(r.app);
+ }
+
+ private static long getInputDispatchingTimeoutLocked(WindowProcessController r) {
+ if (r != null && (r.isInstrumenting() || r.isUsingWrapper())) {
+ return INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT_MS;
+ }
+ return KEY_DISPATCHING_TIMEOUT_MS;
+ }
+
+ long inputDispatchingTimedOut(int pid, final boolean aboveSystem, String reason) {
+ if (checkCallingPermission(FILTER_EVENTS) != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Requires permission " + FILTER_EVENTS);
+ }
+ WindowProcessController proc;
+ long timeout;
+ synchronized (mGlobalLock) {
+ proc = mPidMap.get(pid);
+ timeout = getInputDispatchingTimeoutLocked(proc);
+ }
+
+ if (inputDispatchingTimedOut(proc, null, null, aboveSystem, reason)) {
+ return -1;
+ }
+
+ return timeout;
+ }
+
+ /**
+ * Handle input dispatching timeouts.
+ * Returns whether input dispatching should be aborted or not.
+ */
+ boolean inputDispatchingTimedOut(final WindowProcessController proc,
+ final ActivityRecord activity, final ActivityRecord parent,
+ final boolean aboveSystem, String reason) {
+ if (checkCallingPermission(FILTER_EVENTS) != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Requires permission " + FILTER_EVENTS);
+ }
+
+ final String annotation;
+ if (reason == null) {
+ annotation = "Input dispatching timed out";
+ } else {
+ annotation = "Input dispatching timed out (" + reason + ")";
+ }
+
+ if (proc != null) {
+ synchronized (mGlobalLock) {
+ if (proc.isDebugging()) {
+ return false;
+ }
+
+ if (proc.isInstrumenting()) {
+ Bundle info = new Bundle();
+ info.putString("shortMsg", "keyDispatchingTimedOut");
+ info.putString("longMsg", annotation);
+ mAm.finishInstrumentationLocked(
+ (ProcessRecord) proc.mOwner, Activity.RESULT_CANCELED, info);
+ return true;
+ }
+ }
+ mH.post(() -> {
+ mAm.mAppErrors.appNotResponding(
+ (ProcessRecord) proc.mOwner, activity, parent, aboveSystem, annotation);
+ });
+ }
+
+ return true;
+ }
+
/**
* Decide based on the configuration whether we should show the ANR,
* crash, etc dialogs. The idea is that if there is no affordance to
@@ -4784,6 +4863,26 @@
return kept;
}
+ void scheduleAppGcsLocked() {
+ mH.post(() -> mAmInternal.scheduleAppGcs());
+ }
+
+ /**
+ * Returns the PackageManager. Used by classes hosted by {@link ActivityTaskManagerService}. The
+ * PackageManager could be unavailable at construction time and therefore needs to be accessed
+ * on demand.
+ */
+ IPackageManager getPackageManager() {
+ return AppGlobals.getPackageManager();
+ }
+
+ PackageManagerInternal getPackageManagerInternalLocked() {
+ if (mPmInternal == null) {
+ mPmInternal = LocalServices.getService(PackageManagerInternal.class);
+ }
+ return mPmInternal;
+ }
+
void logAppTooSlow(WindowProcessController app, long startTime, String msg) {
if (true || Build.IS_USER) {
return;
@@ -5232,5 +5331,27 @@
}
}
}
+
+ @Override
+ public long inputDispatchingTimedOut(int pid, boolean aboveSystem, String reason) {
+ synchronized (mGlobalLock) {
+ return ActivityTaskManagerService.this.inputDispatchingTimedOut(
+ pid, aboveSystem, reason);
+ }
+ }
+
+ @Override
+ public void onProcessMapped(int pid, WindowProcessController proc) {
+ synchronized (mGlobalLock) {
+ mPidMap.put(pid, proc);
+ }
+ }
+
+ @Override
+ public void onProcessUnMapped(int pid) {
+ synchronized (mGlobalLock) {
+ mPidMap.remove(pid);
+ }
+ }
}
}
diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java
index 7652dd4..2c58094 100644
--- a/services/core/java/com/android/server/am/AppErrors.java
+++ b/services/core/java/com/android/server/am/AppErrors.java
@@ -436,7 +436,7 @@
* If this process was running instrumentation, finish now - it will be handled in
* {@link ActivityManagerService#handleAppDiedLocked}.
*/
- if (r != null && r.instr != null) {
+ if (r != null && r.getActiveInstrumentation() != null) {
return;
}
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index 046cfc7..b36b5d3 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -1462,7 +1462,7 @@
// If the receiver app is being debugged we quietly ignore unresponsiveness, just
// tidying up and moving on to the next broadcast without crashing or ANRing this
// app just because it's stopped at a breakpoint.
- final boolean debugging = (r.curApp != null && r.curApp.debugging);
+ final boolean debugging = (r.curApp != null && r.curApp.isDebugging());
Slog.w(TAG, "Timeout of broadcast " + r + " - receiver=" + r.receiver
+ ", started " + (now - r.receiverTime) + "ms ago");
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index b33ce2b..8c552b9 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -187,8 +187,9 @@
int lruSeq; // Sequence id for identifying LRU update cycles
CompatibilityInfo compat; // last used compatibility mode
IBinder.DeathRecipient deathRecipient; // Who is watching for the death.
- ActiveInstrumentation instr;// Set to currently active instrumentation running in process
- boolean usingWrapper; // Set to true when process was launched with a wrapper attached
+ private ActiveInstrumentation mInstr; // Set to currently active instrumentation running in
+ // process.
+ private boolean mUsingWrapper; // Set to true when process was launched with a wrapper attached
final ArraySet<BroadcastRecord> curReceivers = new ArraySet<BroadcastRecord>();// receivers currently running in the app
long whenUnimportant; // When (uptime) the process last became unimportant
long lastCpuTime; // How long proc has run CPU at last check
@@ -232,7 +233,7 @@
private boolean mNotResponding; // does the app have a not responding dialog?
Dialog anrDialog; // dialog being displayed due to app not resp.
boolean removed; // has app package been removed from device?
- boolean debugging; // was app launched for debugging?
+ private boolean mDebugging; // was app launched for debugging?
boolean waitedForDebugger; // has process show wait for debugger dialog?
Dialog waitDialog; // current wait for debugger dialog
@@ -317,8 +318,8 @@
pw.println("}");
}
pw.print(prefix); pw.print("compat="); pw.println(compat);
- if (instr != null) {
- pw.print(prefix); pw.print("instr="); pw.println(instr);
+ if (mInstr != null) {
+ pw.print(prefix); pw.print("mInstr="); pw.println(mInstr);
}
pw.print(prefix); pw.print("thread="); pw.println(thread);
pw.print(prefix); pw.print("pid="); pw.print(pid); pw.print(" starting=");
@@ -435,9 +436,9 @@
pw.print(" killedByAm="); pw.print(killedByAm);
pw.print(" waitingToKill="); pw.println(waitingToKill);
}
- if (debugging || mCrashing || crashDialog != null || mNotResponding
+ if (mDebugging || mCrashing || crashDialog != null || mNotResponding
|| anrDialog != null || bad) {
- pw.print(prefix); pw.print("debugging="); pw.print(debugging);
+ pw.print(prefix); pw.print("mDebugging="); pw.print(mDebugging);
pw.print(" mCrashing="); pw.print(mCrashing);
pw.print(" "); pw.print(crashDialog);
pw.print(" mNotResponding="); pw.print(mNotResponding);
@@ -975,6 +976,33 @@
return mHasForegroundServices;
}
+ void setDebugging(boolean debugging) {
+ mDebugging = debugging;
+ mWindowProcessController.setDebugging(debugging);
+ }
+
+ boolean isDebugging() {
+ return mDebugging;
+ }
+
+ void setUsingWrapper(boolean usingWrapper) {
+ mUsingWrapper = usingWrapper;
+ mWindowProcessController.setUsingWrapper(usingWrapper);
+ }
+
+ boolean isUsingWrapper() {
+ return mUsingWrapper;
+ }
+
+ void setActiveInstrumentation(ActiveInstrumentation instr) {
+ mInstr = instr;
+ mWindowProcessController.setInstrumenting(instr != null);
+ }
+
+ ActiveInstrumentation getActiveInstrumentation() {
+ return mInstr;
+ }
+
@Override
public void clearProfilerIfNeeded() {
synchronized (mService) {
diff --git a/services/core/java/com/android/server/am/RecentTasks.java b/services/core/java/com/android/server/am/RecentTasks.java
index 230810b..fb6b5c1 100644
--- a/services/core/java/com/android/server/am/RecentTasks.java
+++ b/services/core/java/com/android/server/am/RecentTasks.java
@@ -288,7 +288,7 @@
* @return whether the home app is also the active handler of recent tasks.
*/
boolean isRecentsComponentHomeActivity(int userId) {
- final ComponentName defaultHomeActivity = mService.mAm.getPackageManagerInternalLocked()
+ final ComponentName defaultHomeActivity = mService.getPackageManagerInternalLocked()
.getDefaultHomeActivity(userId);
return defaultHomeActivity != null && mRecentsComponent != null &&
defaultHomeActivity.getPackageName().equals(mRecentsComponent.getPackageName());
diff --git a/services/core/java/com/android/server/am/WindowProcessController.java b/services/core/java/com/android/server/am/WindowProcessController.java
index d4c9bcb..e5551b5 100644
--- a/services/core/java/com/android/server/am/WindowProcessController.java
+++ b/services/core/java/com/android/server/am/WindowProcessController.java
@@ -93,6 +93,12 @@
private volatile String mRequiredAbi;
// Running any services that are foreground?
private volatile boolean mHasForegroundServices;
+ // was app launched for debugging?
+ private volatile boolean mDebugging;
+ // Active instrumentation running in process?
+ private volatile boolean mInstrumenting;
+ // Set to true when process was launched with a wrapper attached
+ private volatile boolean mUsingWrapper;
// Thread currently set for VR scheduling
int mVrThreadTid;
@@ -189,6 +195,30 @@
return mRequiredAbi;
}
+ public void setDebugging(boolean debugging) {
+ mDebugging = debugging;
+ }
+
+ boolean isDebugging() {
+ return mDebugging;
+ }
+
+ public void setUsingWrapper(boolean usingWrapper) {
+ mUsingWrapper = usingWrapper;
+ }
+
+ boolean isUsingWrapper() {
+ return mUsingWrapper;
+ }
+
+ public void setInstrumenting(boolean instrumenting) {
+ mInstrumenting = instrumenting;
+ }
+
+ boolean isInstrumenting() {
+ return mInstrumenting;
+ }
+
public void addPackage(String packageName) {
synchronized (mAtm.mGlobalLock) {
mPkgList.add(packageName);
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
index bfecd9d..7dd2dda 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
@@ -274,4 +274,8 @@
public abstract void enableScreenAfterBoot(boolean booted);
public abstract boolean showStrictModeViolationDialog();
public abstract void showSystemReadyErrorDialogsIfNeeded();
+
+ public abstract long inputDispatchingTimedOut(int pid, boolean aboveSystem, String reason);
+ public abstract void onProcessMapped(int pid, WindowProcessController proc);
+ public abstract void onProcessUnMapped(int pid);
}
diff --git a/services/core/java/com/android/server/wm/InputManagerCallback.java b/services/core/java/com/android/server/wm/InputManagerCallback.java
index 016921d..b5e2f01 100644
--- a/services/core/java/com/android/server/wm/InputManagerCallback.java
+++ b/services/core/java/com/android/server/wm/InputManagerCallback.java
@@ -123,17 +123,14 @@
return appWindowToken.mInputDispatchingTimeoutNanos;
}
} else if (windowState != null) {
- try {
- // Notify the activity manager about the timeout and let it decide whether
- // to abort dispatching or keep waiting.
- long timeout = ActivityManager.getService().inputDispatchingTimedOut(
- windowState.mSession.mPid, aboveSystem, reason);
- if (timeout >= 0) {
- // The activity manager declined to abort dispatching.
- // Wait a bit longer and timeout again later.
- return timeout * 1000000L; // nanoseconds
- }
- } catch (RemoteException ex) {
+ // Notify the activity manager about the timeout and let it decide whether
+ // to abort dispatching or keep waiting.
+ long timeout = mService.mAtmInternal.inputDispatchingTimedOut(
+ windowState.mSession.mPid, aboveSystem, reason);
+ if (timeout >= 0) {
+ // The activity manager declined to abort dispatching.
+ // Wait a bit longer and timeout again later.
+ return timeout * 1000000L; // nanoseconds
}
}
return 0; // abort dispatching