summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/app/ActivityThread.java25
-rw-r--r--core/java/android/app/ForegroundServiceDidNotStartInTimeException.java33
-rw-r--r--core/java/android/app/IActivityManager.aidl2
-rw-r--r--core/java/android/app/IApplicationThread.aidl2
-rw-r--r--core/java/android/app/RemoteServiceException.java38
-rw-r--r--core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java2
-rw-r--r--services/core/java/com/android/server/am/ActiveServices.java6
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java10
-rw-r--r--services/core/java/com/android/server/am/AppErrors.java4
-rw-r--r--services/core/java/com/android/server/am/ProcessRecord.java18
10 files changed, 123 insertions, 17 deletions
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index e596e7c2ab06..e50432eaa299 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -236,12 +236,6 @@ import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
-final class RemoteServiceException extends AndroidRuntimeException {
- public RemoteServiceException(String msg) {
- super(msg);
- }
-}
-
/**
* This manages the execution of the main thread in an
* application process, scheduling and executing activities,
@@ -1274,8 +1268,9 @@ public final class ActivityThread extends ClientTransactionHandler
sendMessage(H.DISPATCH_PACKAGE_BROADCAST, packages, cmd);
}
- public void scheduleCrash(String msg) {
- sendMessage(H.SCHEDULE_CRASH, msg);
+ @Override
+ public void scheduleCrash(String msg, int typeId) {
+ sendMessage(H.SCHEDULE_CRASH, msg, typeId);
}
public void dumpActivity(ParcelFileDescriptor pfd, IBinder activitytoken,
@@ -1892,6 +1887,17 @@ public final class ActivityThread extends ClientTransactionHandler
}
}
+ private void throwRemoteServiceException(String message, int typeId) {
+ // Use a switch to ensure all the type IDs are unique.
+ switch (typeId) {
+ case ForegroundServiceDidNotStartInTimeException.TYPE_ID: // 1
+ throw new ForegroundServiceDidNotStartInTimeException(message);
+ case RemoteServiceException.TYPE_ID: // 0
+ default:
+ throw new RemoteServiceException(message);
+ }
+ }
+
class H extends Handler {
public static final int BIND_APPLICATION = 110;
@UnsupportedAppUsage
@@ -2105,7 +2111,8 @@ public final class ActivityThread extends ClientTransactionHandler
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
case SCHEDULE_CRASH:
- throw new RemoteServiceException((String)msg.obj);
+ throwRemoteServiceException((String) msg.obj, msg.arg1);
+ break;
case DUMP_HEAP:
handleDumpHeap((DumpHeapData) msg.obj);
break;
diff --git a/core/java/android/app/ForegroundServiceDidNotStartInTimeException.java b/core/java/android/app/ForegroundServiceDidNotStartInTimeException.java
new file mode 100644
index 000000000000..364291e69ad6
--- /dev/null
+++ b/core/java/android/app/ForegroundServiceDidNotStartInTimeException.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app;
+
+/**
+ * Exception used to crash an app process when it didn't call {@link Service#startForeground}
+ * in time after the service was started with
+ * {@link android.content.Context#startForegroundService}.
+ *
+ * @hide
+ */
+public class ForegroundServiceDidNotStartInTimeException extends RemoteServiceException {
+ /** The type ID passed to {@link IApplicationThread#scheduleCrash}. */
+ public static final int TYPE_ID = 1;
+
+ public ForegroundServiceDidNotStartInTimeException(String msg) {
+ super(msg);
+ }
+}
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index 1b8eb8add791..f9279da172a0 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -321,6 +321,8 @@ interface IActivityManager {
boolean isTopActivityImmersive();
void crashApplication(int uid, int initialPid, in String packageName, int userId,
in String message, boolean force);
+ void crashApplicationWithType(int uid, int initialPid, in String packageName, int userId,
+ in String message, boolean force, int exceptionTypeId);
/** @deprecated -- use getProviderMimeTypeAsync */
@UnsupportedAppUsage(maxTargetSdk = 29, publicAlternatives =
"Use {@link android.content.ContentResolver#getType} public API instead.")
diff --git a/core/java/android/app/IApplicationThread.aidl b/core/java/android/app/IApplicationThread.aidl
index b5294d5b6f4e..78e7ce8c594e 100644
--- a/core/java/android/app/IApplicationThread.aidl
+++ b/core/java/android/app/IApplicationThread.aidl
@@ -106,7 +106,7 @@ oneway interface IApplicationThread {
void scheduleOnNewActivityOptions(IBinder token, in Bundle options);
void scheduleSuicide();
void dispatchPackageBroadcast(int cmd, in String[] packages);
- void scheduleCrash(in String msg);
+ void scheduleCrash(in String msg, int typeId);
void dumpHeap(boolean managed, boolean mallocInfo, boolean runGc, in String path,
in ParcelFileDescriptor fd, in RemoteCallback finishCallback);
void dumpActivity(in ParcelFileDescriptor fd, IBinder servicetoken, in String prefix,
diff --git a/core/java/android/app/RemoteServiceException.java b/core/java/android/app/RemoteServiceException.java
new file mode 100644
index 000000000000..4b32463e2996
--- /dev/null
+++ b/core/java/android/app/RemoteServiceException.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app;
+
+import android.util.AndroidRuntimeException;
+
+/**
+ * Exception used by {@link ActivityThread} to crash an app process.
+ *
+ * @hide
+ */
+public class RemoteServiceException extends AndroidRuntimeException {
+ /**
+ * The type ID passed to {@link IApplicationThread#scheduleCrash}.
+ *
+ * Assign a unique ID to each subclass. See the above method for the numbers that are already
+ * taken.
+ */
+ public static final int TYPE_ID = 0;
+
+ public RemoteServiceException(String msg) {
+ super(msg);
+ }
+}
diff --git a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
index f47fa39e7dc8..4dbdc606497e 100644
--- a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
+++ b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
@@ -531,7 +531,7 @@ public class TransactionParcelTests {
}
@Override
- public void scheduleCrash(String s) throws RemoteException {
+ public void scheduleCrash(String s, int i) throws RemoteException {
}
@Override
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index c1ab6cc89eac..c7f2f43db131 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -78,6 +78,7 @@ import android.app.ActivityManagerInternal;
import android.app.ActivityThread;
import android.app.AppGlobals;
import android.app.AppOpsManager;
+import android.app.ForegroundServiceDidNotStartInTimeException;
import android.app.ForegroundServiceStartNotAllowedException;
import android.app.IApplicationThread;
import android.app.IServiceConnection;
@@ -4988,9 +4989,10 @@ public final class ActiveServices {
}
void serviceForegroundCrash(ProcessRecord app, CharSequence serviceRecord) {
- mAm.crashApplication(app.uid, app.getPid(), app.info.packageName, app.userId,
+ mAm.crashApplicationWithType(app.uid, app.getPid(), app.info.packageName, app.userId,
"Context.startForegroundService() did not then call Service.startForeground(): "
- + serviceRecord, false /*force*/);
+ + serviceRecord, false /*force*/,
+ ForegroundServiceDidNotStartInTimeException.TYPE_ID);
}
void scheduleServiceTimeoutLocked(ProcessRecord proc) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 7dc39b34c88a..ac042a780a36 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -179,6 +179,7 @@ import android.app.PendingIntent;
import android.app.ProcessMemoryState;
import android.app.ProfilerInfo;
import android.app.PropertyInvalidatedCache;
+import android.app.RemoteServiceException;
import android.app.SyncNotedAppOp;
import android.app.WaitResult;
import android.app.backup.BackupManager.OperationType;
@@ -2935,6 +2936,13 @@ public class ActivityManagerService extends IActivityManager.Stub
@Override
public void crashApplication(int uid, int initialPid, String packageName, int userId,
String message, boolean force) {
+ crashApplicationWithType(uid, initialPid, packageName, userId, message, force,
+ RemoteServiceException.TYPE_ID);
+ }
+
+ @Override
+ public void crashApplicationWithType(int uid, int initialPid, String packageName, int userId,
+ String message, boolean force, int exceptionTypeId) {
if (checkCallingPermission(android.Manifest.permission.FORCE_STOP_PACKAGES)
!= PackageManager.PERMISSION_GRANTED) {
String msg = "Permission Denial: crashApplication() from pid="
@@ -2947,7 +2955,7 @@ public class ActivityManagerService extends IActivityManager.Stub
synchronized(this) {
mAppErrors.scheduleAppCrashLocked(uid, initialPid, packageName, userId,
- message, force);
+ message, force, exceptionTypeId);
}
}
diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java
index 3602f44cd785..5a59eabde6f0 100644
--- a/services/core/java/com/android/server/am/AppErrors.java
+++ b/services/core/java/com/android/server/am/AppErrors.java
@@ -486,7 +486,7 @@ class AppErrors {
* @param message
*/
void scheduleAppCrashLocked(int uid, int initialPid, String packageName, int userId,
- String message, boolean force) {
+ String message, boolean force, int exceptionTypeId) {
ProcessRecord proc = null;
// Figure out which process to kill. We don't trust that initialPid
@@ -518,7 +518,7 @@ class AppErrors {
return;
}
- proc.scheduleCrashLocked(message);
+ proc.scheduleCrashLocked(message, exceptionTypeId);
if (force) {
// If the app is responsive, the scheduled crash will happen as expected
// and then the delayed summary kill will be a no-op.
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index ed136afcc592..9e94d4aa2c0f 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -26,6 +26,7 @@ import android.app.ApplicationExitInfo;
import android.app.ApplicationExitInfo.Reason;
import android.app.ApplicationExitInfo.SubReason;
import android.app.IApplicationThread;
+import android.app.RemoteServiceException;
import android.content.pm.ApplicationInfo;
import android.content.pm.ProcessInfo;
import android.content.pm.VersionedPackage;
@@ -949,6 +950,21 @@ class ProcessRecord implements WindowProcessListener {
@GuardedBy("mService")
void scheduleCrashLocked(String message) {
+ scheduleCrashLocked(message, RemoteServiceException.TYPE_ID);
+ }
+
+ /**
+ * Let an app process throw an exception on a binder thread, which typically crashes the
+ * process, unless it has an unhandled exception handler.
+ *
+ * See {@link ActivityThread#throwRemoteServiceException}.
+ *
+ * @param message exception message
+ * @param exceptionTypeId ID defined in {@link android.app.RemoteServiceException} or one
+ * of its subclasses.
+ */
+ @GuardedBy("mService")
+ void scheduleCrashLocked(String message, int exceptionTypeId) {
// Checking killedbyAm should keep it from showing the crash dialog if the process
// was already dead for a good / normal reason.
if (!mKilledByAm) {
@@ -959,7 +975,7 @@ class ProcessRecord implements WindowProcessListener {
}
final long ident = Binder.clearCallingIdentity();
try {
- mThread.scheduleCrash(message);
+ mThread.scheduleCrash(message, exceptionTypeId);
} catch (RemoteException e) {
// If it's already dead our work is done. If it's wedged just kill it.
// We won't get the crash dialog or the error reporting.