summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDianne Hackborn <hackbod@google.com>2010-06-24 15:57:42 -0700
committerDianne Hackborn <hackbod@google.com>2010-06-24 17:27:28 -0700
commit9d39d0cb361c5d3bba04a6bacf299be2162a6e92 (patch)
tree3e08cfc2e7b5e1fabc21d2c0c9184531da78d41a
parent01e4cfc47d0a2c7e7ab383d2fb23224ec52c0301 (diff)
downloadframeworks_base-9d39d0cb361c5d3bba04a6bacf299be2162a6e92.zip
frameworks_base-9d39d0cb361c5d3bba04a6bacf299be2162a6e92.tar.gz
frameworks_base-9d39d0cb361c5d3bba04a6bacf299be2162a6e92.tar.bz2
Make bad notifications crash their application.
Implement notification manager handling of bad notifications, to call a new activity manager to have the owner's process crashed (if there is one). Change-Id: Ib15e8d0c598756f3b39c99cc2045c18e054daf6b
-rw-r--r--core/java/android/app/ActivityManagerNative.java26
-rw-r--r--core/java/android/app/ActivityThread.java14
-rw-r--r--core/java/android/app/ApplicationThreadNative.java18
-rw-r--r--core/java/android/app/IActivityManager.java4
-rw-r--r--core/java/android/app/IApplicationThread.java2
-rw-r--r--core/java/com/android/internal/statusbar/IStatusBarService.aidl3
-rw-r--r--core/java/com/android/internal/statusbar/StatusBarNotification.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/PhoneStatusBarService.java2
-rwxr-xr-xservices/java/com/android/server/NotificationManagerService.java28
-rw-r--r--services/java/com/android/server/StatusBarManagerService.java8
-rw-r--r--services/java/com/android/server/am/ActivityManagerService.java54
11 files changed, 161 insertions, 12 deletions
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 63b2f08..e56fee9 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -1293,6 +1293,17 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
return true;
}
+ case CRASH_APPLICATION_TRANSACTION: {
+ data.enforceInterface(IActivityManager.descriptor);
+ int uid = data.readInt();
+ int initialPid = data.readInt();
+ String packageName = data.readString();
+ String message = data.readString();
+ crashApplication(uid, initialPid, packageName, message);
+ reply.writeNoException();
+ return true;
+ }
+
}
return super.onTransact(code, data, reply, flags);
@@ -2867,5 +2878,20 @@ class ActivityManagerProxy implements IActivityManager
return res;
}
+ public void crashApplication(int uid, int initialPid, String packageName,
+ String message) throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ data.writeInt(uid);
+ data.writeInt(initialPid);
+ data.writeString(packageName);
+ data.writeString(message);
+ mRemote.transact(CRASH_APPLICATION_TRANSACTION, data, reply, 0);
+ reply.readException();
+ data.recycle();
+ reply.recycle();
+ }
+
private IBinder mRemote;
}
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 6599096..03bb858 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -99,6 +99,12 @@ final class SuperNotCalledException extends AndroidRuntimeException {
}
}
+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,
@@ -644,6 +650,10 @@ public final class ActivityThread {
public void dispatchPackageBroadcast(int cmd, String[] packages) {
queueOrSendMessage(H.DISPATCH_PACKAGE_BROADCAST, packages, cmd);
}
+
+ public void scheduleCrash(String msg) {
+ queueOrSendMessage(H.SCHEDULE_CRASH, msg);
+ }
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
@@ -870,6 +880,7 @@ public final class ActivityThread {
public static final int REMOVE_PROVIDER = 131;
public static final int ENABLE_JIT = 132;
public static final int DISPATCH_PACKAGE_BROADCAST = 133;
+ public static final int SCHEDULE_CRASH = 134;
String codeToString(int code) {
if (localLOGV) {
switch (code) {
@@ -907,6 +918,7 @@ public final class ActivityThread {
case REMOVE_PROVIDER: return "REMOVE_PROVIDER";
case ENABLE_JIT: return "ENABLE_JIT";
case DISPATCH_PACKAGE_BROADCAST: return "DISPATCH_PACKAGE_BROADCAST";
+ case SCHEDULE_CRASH: return "SCHEDULE_CRASH";
}
}
return "(unknown)";
@@ -1030,6 +1042,8 @@ public final class ActivityThread {
case DISPATCH_PACKAGE_BROADCAST:
handleDispatchPackageBroadcast(msg.arg1, (String[])msg.obj);
break;
+ case SCHEDULE_CRASH:
+ throw new RemoteServiceException((String)msg.obj);
}
}
diff --git a/core/java/android/app/ApplicationThreadNative.java b/core/java/android/app/ApplicationThreadNative.java
index da26a78..360959d 100644
--- a/core/java/android/app/ApplicationThreadNative.java
+++ b/core/java/android/app/ApplicationThreadNative.java
@@ -402,6 +402,14 @@ public abstract class ApplicationThreadNative extends Binder
dispatchPackageBroadcast(cmd, packages);
return true;
}
+
+ case SCHEDULE_CRASH_TRANSACTION:
+ {
+ data.enforceInterface(IApplicationThread.descriptor);
+ String msg = data.readString();
+ scheduleCrash(msg);
+ return true;
+ }
}
return super.onTransact(code, data, reply, flags);
@@ -826,5 +834,15 @@ class ApplicationThreadProxy implements IApplicationThread {
data.recycle();
}
+
+ public void scheduleCrash(String msg) throws RemoteException {
+ Parcel data = Parcel.obtain();
+ data.writeInterfaceToken(IApplicationThread.descriptor);
+ data.writeString(msg);
+ mRemote.transact(SCHEDULE_CRASH_TRANSACTION, data, null,
+ IBinder.FLAG_ONEWAY);
+ data.recycle();
+
+ }
}
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 3a86ead..bf02d5a 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -316,6 +316,9 @@ public interface IActivityManager extends IInterface {
public boolean isImmersive(IBinder token) throws RemoteException;
public boolean isTopActivityImmersive() throws RemoteException;
+ public void crashApplication(int uid, int initialPid, String packageName,
+ String message) throws RemoteException;
+
/*
* Private non-Binder interfaces
*/
@@ -531,4 +534,5 @@ public interface IActivityManager extends IInterface {
int IS_IMMERSIVE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+110;
int SET_IMMERSIVE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+111;
int IS_TOP_ACTIVITY_IMMERSIVE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+112;
+ int CRASH_APPLICATION_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+113;
}
diff --git a/core/java/android/app/IApplicationThread.java b/core/java/android/app/IApplicationThread.java
index c917e81..ffb8651 100644
--- a/core/java/android/app/IApplicationThread.java
+++ b/core/java/android/app/IApplicationThread.java
@@ -103,6 +103,7 @@ public interface IApplicationThread extends IInterface {
static final int PACKAGE_REMOVED = 0;
static final int EXTERNAL_STORAGE_UNAVAILABLE = 1;
void dispatchPackageBroadcast(int cmd, String[] packages) throws RemoteException;
+ void scheduleCrash(String msg) throws RemoteException;
String descriptor = "android.app.IApplicationThread";
@@ -139,4 +140,5 @@ public interface IApplicationThread extends IInterface {
int GET_MEMORY_INFO_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+31;
int SCHEDULE_SUICIDE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+32;
int DISPATCH_PACKAGE_BROADCAST_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+33;
+ int SCHEDULE_CRASH_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+34;
}
diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
index 045c24f..852630d 100644
--- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
@@ -37,6 +37,7 @@ interface IStatusBarService
out List<IBinder> notificationKeys, out List<StatusBarNotification> notifications);
void onPanelRevealed();
void onNotificationClick(String pkg, String tag, int id);
- void onNotificationError(String pkg, String tag, int id, String message);
+ void onNotificationError(String pkg, String tag, int id,
+ int uid, int initialPid, String message);
void onClearAllNotifications();
}
diff --git a/core/java/com/android/internal/statusbar/StatusBarNotification.java b/core/java/com/android/internal/statusbar/StatusBarNotification.java
index 5499676..aa340fb 100644
--- a/core/java/com/android/internal/statusbar/StatusBarNotification.java
+++ b/core/java/com/android/internal/statusbar/StatusBarNotification.java
@@ -38,18 +38,23 @@ public class StatusBarNotification implements Parcelable {
public String pkg;
public int id;
public String tag;
+ public int uid;
+ public int initialPid;
public Notification notification;
public StatusBarNotification() {
}
- public StatusBarNotification(String pkg, int id, String tag, Notification notification) {
+ public StatusBarNotification(String pkg, int id, String tag,
+ int uid, int initialPid, Notification notification) {
if (pkg == null) throw new NullPointerException();
if (notification == null) throw new NullPointerException();
this.pkg = pkg;
this.id = id;
this.tag = tag;
+ this.uid = uid;
+ this.initialPid = initialPid;
this.notification = notification;
}
@@ -65,6 +70,8 @@ public class StatusBarNotification implements Parcelable {
} else {
this.tag = null;
}
+ this.uid = in.readInt();
+ this.initialPid = in.readInt();
this.notification = new Notification(in);
}
@@ -77,6 +84,8 @@ public class StatusBarNotification implements Parcelable {
} else {
out.writeInt(0);
}
+ out.writeInt(this.uid);
+ out.writeInt(this.initialPid);
this.notification.writeToParcel(out, flags);
}
@@ -99,7 +108,8 @@ public class StatusBarNotification implements Parcelable {
};
public StatusBarNotification clone() {
- return new StatusBarNotification(this.pkg, this.id, this.tag, this.notification.clone());
+ return new StatusBarNotification(this.pkg, this.id, this.tag,
+ this.uid, this.initialPid, this.notification.clone());
}
public String toString() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/PhoneStatusBarService.java b/packages/SystemUI/src/com/android/systemui/statusbar/PhoneStatusBarService.java
index a7e5e31..801cb91 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/PhoneStatusBarService.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/PhoneStatusBarService.java
@@ -989,7 +989,7 @@ public class PhoneStatusBarService extends StatusBarService {
void handleNotificationError(IBinder key, StatusBarNotification n, String message) {
removeNotification(key);
try {
- mBarService.onNotificationError(n.pkg, n.tag, n.id, message);
+ mBarService.onNotificationError(n.pkg, n.tag, n.id, n.uid, n.initialPid, message);
} catch (RemoteException ex) {
// The end is nigh.
}
diff --git a/services/java/com/android/server/NotificationManagerService.java b/services/java/com/android/server/NotificationManagerService.java
index 6f44e8e..3e2c122 100755
--- a/services/java/com/android/server/NotificationManagerService.java
+++ b/services/java/com/android/server/NotificationManagerService.java
@@ -164,16 +164,21 @@ class NotificationManagerService extends INotificationManager.Stub
final String pkg;
final String tag;
final int id;
+ final int uid;
+ final int initialPid;
ITransientNotification callback;
int duration;
final Notification notification;
IBinder statusBarKey;
- NotificationRecord(String pkg, String tag, int id, Notification notification)
+ NotificationRecord(String pkg, String tag, int id, int uid, int initialPid,
+ Notification notification)
{
this.pkg = pkg;
this.tag = tag;
this.id = id;
+ this.uid = uid;
+ this.initialPid = initialPid;
this.notification = notification;
}
@@ -304,10 +309,18 @@ class NotificationManagerService extends INotificationManager.Stub
}
}
- public void onNotificationError(String pkg, String tag, int id, String message) {
+ public void onNotificationError(String pkg, String tag, int id,
+ int uid, int initialPid, String message) {
Slog.d(TAG, "onNotification error pkg=" + pkg + " tag=" + tag + " id=" + id);
cancelNotification(pkg, tag, id, 0, 0);
- // TODO: Tell the activity manager.
+ long ident = Binder.clearCallingIdentity();
+ try {
+ ActivityManagerNative.getDefault().crashApplication(uid, initialPid, pkg,
+ "Bad notification posted from package " + pkg
+ + ": " + message);
+ } catch (RemoteException e) {
+ }
+ Binder.restoreCallingIdentity(ident);
}
};
@@ -663,6 +676,9 @@ class NotificationManagerService extends INotificationManager.Stub
public void enqueueNotificationWithTag(String pkg, String tag, int id,
Notification notification, int[] idOut)
{
+ final int callingUid = Binder.getCallingUid();
+ final int callingPid = Binder.getCallingPid();
+
checkIncomingCall(pkg);
// Limit the number of notifications that any given package except the android
@@ -708,7 +724,8 @@ class NotificationManagerService extends INotificationManager.Stub
}
synchronized (mNotificationList) {
- NotificationRecord r = new NotificationRecord(pkg, tag, id, notification);
+ NotificationRecord r = new NotificationRecord(pkg, tag, id,
+ callingUid, callingPid, notification);
NotificationRecord old = null;
int index = indexOfNotificationLocked(pkg, tag, id);
@@ -732,7 +749,8 @@ class NotificationManagerService extends INotificationManager.Stub
}
if (notification.icon != 0) {
- StatusBarNotification n = new StatusBarNotification(pkg, id, tag, notification);
+ StatusBarNotification n = new StatusBarNotification(pkg, id, tag,
+ r.uid, r.initialPid, notification);
if (old != null && old.statusBarKey != null) {
r.statusBarKey = old.statusBarKey;
long identity = Binder.clearCallingIdentity();
diff --git a/services/java/com/android/server/StatusBarManagerService.java b/services/java/com/android/server/StatusBarManagerService.java
index 1a16387..4177432 100644
--- a/services/java/com/android/server/StatusBarManagerService.java
+++ b/services/java/com/android/server/StatusBarManagerService.java
@@ -85,7 +85,8 @@ public class StatusBarManagerService extends IStatusBarService.Stub
void onClearAll();
void onNotificationClick(String pkg, String tag, int id);
void onPanelRevealed();
- void onNotificationError(String pkg, String tag, int id, String message);
+ void onNotificationError(String pkg, String tag, int id,
+ int uid, int initialPid, String message);
}
/**
@@ -293,11 +294,12 @@ public class StatusBarManagerService extends IStatusBarService.Stub
mNotificationCallbacks.onNotificationClick(pkg, tag, id);
}
- public void onNotificationError(String pkg, String tag, int id, String message) {
+ public void onNotificationError(String pkg, String tag, int id,
+ int uid, int initialPid, String message) {
enforceStatusBarService();
// WARNING: this will call back into us to do the remove. Don't hold any locks.
- mNotificationCallbacks.onNotificationError(pkg, tag, id, message);
+ mNotificationCallbacks.onNotificationError(pkg, tag, id, uid, initialPid, message);
}
public void onClearAllNotifications() {
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 0e1eb6f..252392b 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -4562,6 +4562,60 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
}
+ public void crashApplication(int uid, int initialPid, String packageName,
+ String message) {
+ if (checkCallingPermission(android.Manifest.permission.FORCE_STOP_PACKAGES)
+ != PackageManager.PERMISSION_GRANTED) {
+ String msg = "Permission Denial: crashApplication() from pid="
+ + Binder.getCallingPid()
+ + ", uid=" + Binder.getCallingUid()
+ + " requires " + android.Manifest.permission.FORCE_STOP_PACKAGES;
+ Slog.w(TAG, msg);
+ throw new SecurityException(msg);
+ }
+
+ synchronized(this) {
+ ProcessRecord proc = null;
+
+ // Figure out which process to kill. We don't trust that initialPid
+ // still has any relation to current pids, so must scan through the
+ // list.
+ synchronized (mPidsSelfLocked) {
+ for (int i=0; i<mPidsSelfLocked.size(); i++) {
+ ProcessRecord p = mPidsSelfLocked.valueAt(i);
+ if (p.info.uid != uid) {
+ continue;
+ }
+ if (p.pid == initialPid) {
+ proc = p;
+ break;
+ }
+ for (String str : p.pkgList) {
+ if (str.equals(packageName)) {
+ proc = p;
+ }
+ }
+ }
+ }
+
+ if (proc == null) {
+ Log.w(TAG, "crashApplication: nothing for uid=" + uid
+ + " initialPid=" + initialPid
+ + " packageName=" + packageName);
+ return;
+ }
+
+ if (proc.thread != null) {
+ long ident = Binder.clearCallingIdentity();
+ try {
+ proc.thread.scheduleCrash(message);
+ } catch (RemoteException e) {
+ }
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+ }
+
void sendActivityResultLocked(int callingUid, ActivityRecord r,
String resultWho, int requestCode, int resultCode, Intent data) {