Merge "DO NOT MERGE - Kill apps outright for API contract violations" into qt-dev
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index 48ca716..c0c6355 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -287,7 +287,8 @@
void handleApplicationStrictModeViolation(in IBinder app, int penaltyMask,
in StrictMode.ViolationInfo crashInfo);
boolean isTopActivityImmersive();
- void crashApplication(int uid, int initialPid, in String packageName, int userId, in String message);
+ void crashApplication(int uid, int initialPid, in String packageName, int userId,
+ in String message, boolean force);
@UnsupportedAppUsage
String getProviderMimeType(in Uri uri, int userId);
// Cause the specified process to dump the specified heap.
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 7bc2e6d..5d72828 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -829,6 +829,15 @@
}
}
+ void killMisbehavingService(ServiceRecord r,
+ int appUid, int appPid, String localPackageName) {
+ synchronized (mAm) {
+ stopServiceLocked(r);
+ mAm.crashApplication(appUid, appPid, localPackageName, -1,
+ "Bad notification for startForeground", true /*force*/);
+ }
+ }
+
IBinder peekServiceLocked(Intent service, String resolvedType, String callingPackage) {
ServiceLookupResult r = retrieveServiceLocked(service, null, resolvedType, callingPackage,
Binder.getCallingPid(), Binder.getCallingUid(),
@@ -3918,7 +3927,7 @@
void serviceForegroundCrash(ProcessRecord app, CharSequence serviceRecord) {
mAm.crashApplication(app.uid, app.pid, app.info.packageName, app.userId,
"Context.startForegroundService() did not then call Service.startForeground(): "
- + serviceRecord);
+ + serviceRecord, false /*force*/);
}
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 c6cae53..81d636e 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -3568,7 +3568,7 @@
@Override
public void crashApplication(int uid, int initialPid, String packageName, int userId,
- String message) {
+ String message, boolean force) {
if (checkCallingPermission(android.Manifest.permission.FORCE_STOP_PACKAGES)
!= PackageManager.PERMISSION_GRANTED) {
String msg = "Permission Denial: crashApplication() from pid="
@@ -3580,7 +3580,8 @@
}
synchronized(this) {
- mAppErrors.scheduleAppCrashLocked(uid, initialPid, packageName, userId, message);
+ mAppErrors.scheduleAppCrashLocked(uid, initialPid, packageName, userId,
+ message, force);
}
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index cba9674..8f16ed4 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -1051,7 +1051,7 @@
} catch (NumberFormatException e) {
packageName = arg;
}
- mInterface.crashApplication(-1, pid, packageName, userId, "shell-induced crash");
+ mInterface.crashApplication(-1, pid, packageName, userId, "shell-induced crash", false);
return 0;
}
diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java
index 1ff6f4d..6a29c75 100644
--- a/services/core/java/com/android/server/am/AppErrors.java
+++ b/services/core/java/com/android/server/am/AppErrors.java
@@ -314,20 +314,24 @@
}
void killAppAtUserRequestLocked(ProcessRecord app, Dialog fromDialog) {
- app.setCrashing(false);
- app.crashingReport = null;
- app.setNotResponding(false);
- app.notRespondingReport = null;
if (app.anrDialog == fromDialog) {
app.anrDialog = null;
}
if (app.waitDialog == fromDialog) {
app.waitDialog = null;
}
+ killAppImmediateLocked(app, "user-terminated", "user request after error");
+ }
+
+ private void killAppImmediateLocked(ProcessRecord app, String reason, String killReason) {
+ app.setCrashing(false);
+ app.crashingReport = null;
+ app.setNotResponding(false);
+ app.notRespondingReport = null;
if (app.pid > 0 && app.pid != MY_PID) {
- handleAppCrashLocked(app, "user-terminated" /*reason*/,
+ handleAppCrashLocked(app, reason,
null /*shortMsg*/, null /*longMsg*/, null /*stackTrace*/, null /*data*/);
- app.kill("user request after error", true);
+ app.kill(killReason, true);
}
}
@@ -341,7 +345,7 @@
* @param message
*/
void scheduleAppCrashLocked(int uid, int initialPid, String packageName, int userId,
- String message) {
+ String message, boolean force) {
ProcessRecord proc = null;
// Figure out which process to kill. We don't trust that initialPid
@@ -374,6 +378,14 @@
}
proc.scheduleCrash(message);
+ 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.
+ final ProcessRecord p = proc;
+ mService.mHandler.postDelayed(
+ () -> killAppImmediateLocked(p, "forced", "killed for invalid state"),
+ 5000L);
+ }
}
/**
diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java
index dee8e3b..c408695 100644
--- a/services/core/java/com/android/server/am/ServiceRecord.java
+++ b/services/core/java/com/android/server/am/ServiceRecord.java
@@ -798,6 +798,7 @@
final String localPackageName = packageName;
final int localForegroundId = foregroundId;
final Notification _foregroundNoti = foregroundNoti;
+ final ServiceRecord record = this;
ams.mHandler.post(new Runnable() {
public void run() {
NotificationManagerInternal nm = LocalServices.getService(
@@ -896,10 +897,8 @@
Slog.w(TAG, "Error showing notification for service", e);
// If it gave us a garbage notification, it doesn't
// get to be foreground.
- ams.setServiceForeground(instanceName, ServiceRecord.this,
- 0, null, 0, 0);
- ams.crashApplication(appUid, appPid, localPackageName, -1,
- "Bad notification for startForeground: " + e);
+ ams.mServices.killMisbehavingService(record,
+ appUid, appPid, localPackageName);
}
}
});
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index b5f428a..dbd7573 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -892,8 +892,22 @@
@Override
public void onNotificationError(int callingUid, int callingPid, String pkg, String tag,
int id, int uid, int initialPid, String message, int userId) {
+ final boolean fgService;
+ synchronized (mNotificationLock) {
+ NotificationRecord r = findNotificationLocked(pkg, tag, id, userId);
+ fgService = r != null && (r.getNotification().flags & FLAG_FOREGROUND_SERVICE) != 0;
+ }
cancelNotification(callingUid, callingPid, pkg, tag, id, 0, 0, false, userId,
REASON_ERROR, null);
+ if (fgService) {
+ // Still crash for foreground services, preventing the not-crash behaviour abused
+ // by apps to give us a garbage notification and silently start a fg service.
+ Binder.withCleanCallingIdentity(
+ () -> mAm.crashApplication(uid, initialPid, pkg, -1,
+ "Bad notification(tag=" + tag + ", id=" + id + ") posted from package "
+ + pkg + ", crashing app(uid=" + uid + ", pid=" + initialPid + "): "
+ + message, true /* force */));
+ }
}
@Override