...rather than relying on in-app code to perform the shutdown.
Backport of security fix.
Bug:
128649910
Bug:
140108616
Test: manual
Test: atest OsHostTests#testForegroundServiceBadNotification
[basilgello: back-port to 14.1:
- core/java/android/app/IActivityManager.aidl -> core/java/android/app/IActivityManager.java,
- no serviceForegroundCrash in services/core/java/com/android/server/am/ActiveServices.java,
- no runCrash in services/core/java/com/android/server/am/ActivityManagerShellCommand.java,
- add argument to ActivityManagerProxy,
- no mNotificationLock and ForegroundService,
- adjust args count (remove '-1') in killMisbehavingService]
Signed-off-by: Vasyl Gello <vasek.gello@gmail.com>
Change-Id: I94d9de50bb03c33666471e3dbd9c721e9278f7cb
Merged-In: I94d9de50bb03c33666471e3dbd9c721e9278f7cb
(cherry picked from commit
a79b6ba5c59dc6aaa8adbe1ffa3ee4b761f45e7f)
int initialPid = data.readInt();
String packageName = data.readString();
String message = data.readString();
- crashApplication(uid, initialPid, packageName, message);
+ crashApplication(uid, initialPid, packageName, message,
+ false /*force*/);
reply.writeNoException();
return true;
}
}
public void crashApplication(int uid, int initialPid, String packageName,
- String message) throws RemoteException {
+ String message, boolean force) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
public boolean isTopOfTask(IBinder token) throws RemoteException;
public void crashApplication(int uid, int initialPid, String packageName,
- String message) throws RemoteException;
+ String message, boolean force) throws RemoteException;
public String getProviderMimeType(Uri uri, int userId) throws RemoteException;
}
}
+ void killMisbehavingService(ServiceRecord r,
+ int appUid, int appPid, String localPackageName) {
+ synchronized (mAm) {
+ stopServiceLocked(r);
+ mAm.crashApplication(appUid, appPid, localPackageName,
+ "Bad notification for startForeground", true /*force*/);
+ }
+ }
+
IBinder peekServiceLocked(Intent service, String resolvedType, String callingPackage) {
ServiceLookupResult r = retrieveServiceLocked(service, resolvedType, callingPackage,
Binder.getCallingPid(), Binder.getCallingUid(),
@Override
public void crashApplication(int uid, int initialPid, String packageName,
- String message) {
+ String message, boolean force) {
if (checkCallingPermission(android.Manifest.permission.FORCE_STOP_PACKAGES)
!= PackageManager.PERMISSION_GRANTED) {
String msg = "Permission Denial: crashApplication() from pid="
}
synchronized(this) {
- mAppErrors.scheduleAppCrashLocked(uid, initialPid, packageName, message);
+ mAppErrors.scheduleAppCrashLocked(uid, initialPid, packageName,
+ message, force);
}
}
}
void killAppAtUserRequestLocked(ProcessRecord app, Dialog fromDialog) {
- app.crashing = false;
- app.crashingReport = null;
- app.notResponding = 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.crashing = false;
+ app.crashingReport = null;
+ app.notResponding = 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);
}
}
void scheduleAppCrashLocked(int uid, int initialPid, String packageName,
- String message) {
+ String message, boolean force) {
ProcessRecord proc = null;
// Figure out which process to kill. We don't trust that initialPid
}
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);
+ }
}
/**
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(
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(name, ServiceRecord.this,
- 0, null, 0);
- ams.crashApplication(appUid, appPid, localPackageName,
- "Bad notification for startForeground: " + e);
+ ams.mServices.killMisbehavingService(record,
+ appUid, appPid, localPackageName);
}
}
});
try {
ActivityManagerNative.getDefault().crashApplication(uid, initialPid, pkg,
"Bad notification posted from package " + pkg
- + ": " + message);
+ + ": " + message, true /*force*/);
} catch (RemoteException e) {
} finally {
Binder.restoreCallingIdentity(ident);