diff options
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) { |