diff options
Diffstat (limited to 'services/java/com/android/server/NotificationManagerService.java')
| -rwxr-xr-x | services/java/com/android/server/NotificationManagerService.java | 114 |
1 files changed, 72 insertions, 42 deletions
diff --git a/services/java/com/android/server/NotificationManagerService.java b/services/java/com/android/server/NotificationManagerService.java index f6d3b608..3caba1f 100755 --- a/services/java/com/android/server/NotificationManagerService.java +++ b/services/java/com/android/server/NotificationManagerService.java @@ -20,7 +20,9 @@ import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT; import static org.xmlpull.v1.XmlPullParser.END_TAG; import static org.xmlpull.v1.XmlPullParser.START_TAG; +import android.app.ActivityManager; import android.app.ActivityManagerNative; +import android.app.AppGlobals; import android.app.IActivityManager; import android.app.INotificationManager; import android.app.ITransientNotification; @@ -48,11 +50,13 @@ import android.os.Message; import android.os.Process; import android.os.RemoteException; import android.os.ServiceManager; -import android.os.UserId; +import android.os.UserHandle; import android.os.Vibrator; import android.provider.Settings; +import android.service.dreams.IDreamManager; import android.telephony.TelephonyManager; import android.text.TextUtils; +import android.util.AtomicFile; import android.util.EventLog; import android.util.Log; import android.util.Slog; @@ -61,7 +65,6 @@ import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityManager; import android.widget.Toast; -import com.android.internal.os.AtomicFile; import com.android.internal.statusbar.StatusBarNotification; import com.android.internal.util.FastXmlSerializer; @@ -314,17 +317,20 @@ public class NotificationManagerService extends INotificationManager.Stub final int id; final int uid; final int initialPid; + final int userId; final Notification notification; final int score; IBinder statusBarKey; - NotificationRecord(String pkg, String tag, int id, int uid, int initialPid, int score, Notification notification) + NotificationRecord(String pkg, String tag, int id, int uid, int initialPid, + int userId, int score, Notification notification) { this.pkg = pkg; this.tag = tag; this.id = id; this.uid = uid; this.initialPid = initialPid; + this.userId = userId; this.score = score; this.notification = notification; } @@ -339,7 +345,7 @@ public class NotificationManagerService extends INotificationManager.Stub pw.println(prefix + " deleteIntent=" + notification.deleteIntent); pw.println(prefix + " tickerText=" + notification.tickerText); pw.println(prefix + " contentView=" + notification.contentView); - pw.println(prefix + " uid=" + uid); + pw.println(prefix + " uid=" + uid + " userId=" + userId); pw.println(prefix + " defaults=0x" + Integer.toHexString(notification.defaults)); pw.println(prefix + " flags=0x" + Integer.toHexString(notification.flags)); pw.println(prefix + " sound=" + notification.sound); @@ -426,18 +432,25 @@ public class NotificationManagerService extends INotificationManager.Stub } public void onClearAll() { - cancelAll(); + // XXX to be totally correct, the caller should tell us which user + // this is for. + cancelAll(ActivityManager.getCurrentUser()); } public void onNotificationClick(String pkg, String tag, int id) { + // XXX to be totally correct, the caller should tell us which user + // this is for. cancelNotification(pkg, tag, id, Notification.FLAG_AUTO_CANCEL, - Notification.FLAG_FOREGROUND_SERVICE, false); + Notification.FLAG_FOREGROUND_SERVICE, false, + ActivityManager.getCurrentUser()); } public void onNotificationClear(String pkg, String tag, int id) { + // XXX to be totally correct, the caller should tell us which user + // this is for. cancelNotification(pkg, tag, id, 0, Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE, - true); + true, ActivityManager.getCurrentUser()); } public void onPanelRevealed() { @@ -476,7 +489,9 @@ public class NotificationManagerService extends INotificationManager.Stub int uid, int initialPid, String message) { Slog.d(TAG, "onNotification error pkg=" + pkg + " tag=" + tag + " id=" + id + "; will crashApplication(uid=" + uid + ", pid=" + initialPid + ")"); - cancelNotification(pkg, tag, id, 0, 0, false); + // XXX to be totally correct, the caller should tell us which user + // this is for. + cancelNotification(pkg, tag, id, 0, 0, false, UserHandle.getUserId(uid)); long ident = Binder.clearCallingIdentity(); try { ActivityManagerNative.getDefault().crashApplication(uid, initialPid, pkg, @@ -528,7 +543,8 @@ public class NotificationManagerService extends INotificationManager.Stub } if (pkgList != null && (pkgList.length > 0)) { for (String pkgName : pkgList) { - cancelAllNotificationsInt(pkgName, 0, 0, !queryRestart); + cancelAllNotificationsInt(pkgName, 0, 0, !queryRestart, + UserHandle.USER_ALL); } } } else if (action.equals(Intent.ACTION_SCREEN_ON)) { @@ -541,6 +557,11 @@ public class NotificationManagerService extends INotificationManager.Stub mInCall = (intent.getStringExtra(TelephonyManager.EXTRA_STATE).equals( TelephonyManager.EXTRA_STATE_OFFHOOK)); updateNotificationPulse(); + } else if (action.equals(Intent.ACTION_USER_STOPPED)) { + int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1); + if (userHandle >= 0) { + cancelAllNotificationsInt(null, 0, 0, true, userHandle); + } } else if (action.equals(Intent.ACTION_USER_PRESENT)) { // turn off LED when user passes through lock screen mNotificationLight.turnOff(); @@ -616,6 +637,7 @@ public class NotificationManagerService extends INotificationManager.Stub filter.addAction(Intent.ACTION_SCREEN_OFF); filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED); filter.addAction(Intent.ACTION_USER_PRESENT); + filter.addAction(Intent.ACTION_USER_STOPPED); mContext.registerReceiver(mIntentReceiver, filter); IntentFilter pkgFilter = new IntentFilter(); pkgFilter.addAction(Intent.ACTION_PACKAGE_REMOVED); @@ -844,17 +866,11 @@ public class NotificationManagerService extends INotificationManager.Stub // Notifications // ============================================================================ - @Deprecated - public void enqueueNotification(String pkg, int id, Notification notification, int[] idOut) - { - enqueueNotificationWithTag(pkg, null /* tag */, id, notification, idOut); - } - public void enqueueNotificationWithTag(String pkg, String tag, int id, Notification notification, - int[] idOut) + int[] idOut, int userId) { enqueueNotificationInternal(pkg, Binder.getCallingUid(), Binder.getCallingPid(), - tag, id, notification, idOut); + tag, id, notification, idOut, userId); } private final static int clamp(int x, int low, int high) { @@ -865,7 +881,7 @@ public class NotificationManagerService extends INotificationManager.Stub // Not exposed via Binder; for system use only (otherwise malicious apps could spoof the // uid/pid of another application) public void enqueueNotificationInternal(String pkg, int callingUid, int callingPid, - String tag, int id, Notification notification, int[] idOut) + String tag, int id, Notification notification, int[] idOut, int userId) { if (DBG) { Slog.v(TAG, "enqueueNotificationInternal: pkg=" + pkg + " id=" + id + " notification=" + notification); @@ -873,6 +889,9 @@ public class NotificationManagerService extends INotificationManager.Stub checkCallerIsSystemOrSameApp(pkg); final boolean isSystemNotification = ("android".equals(pkg)); + userId = ActivityManager.handleIncomingUser(callingPid, + callingUid, userId, false, true, "enqueueNotification", pkg); + // Limit the number of notifications that any given package except the android // package can enqueue. Prevents DOS attacks and deals with leaks. if (!isSystemNotification) { @@ -947,12 +966,12 @@ public class NotificationManagerService extends INotificationManager.Stub synchronized (mNotificationList) { NotificationRecord r = new NotificationRecord(pkg, tag, id, - callingUid, callingPid, + callingUid, callingPid, userId, score, notification); NotificationRecord old = null; - int index = indexOfNotificationLocked(pkg, tag, id); + int index = indexOfNotificationLocked(pkg, tag, id, userId); if (index < 0) { mNotificationList.add(r); } else { @@ -1014,6 +1033,7 @@ public class NotificationManagerService extends INotificationManager.Stub if (((mDisabledNotifications & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) == 0) && (!(old != null && (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0 )) + && (r.userId == UserHandle.USER_ALL || r.userId == userId) && mSystemReady) { final AudioManager audioManager = (AudioManager) mContext @@ -1173,12 +1193,12 @@ public class NotificationManagerService extends INotificationManager.Stub * and none of the {@code mustNotHaveFlags}. */ private void cancelNotification(String pkg, String tag, int id, int mustHaveFlags, - int mustNotHaveFlags, boolean sendDelete) { + int mustNotHaveFlags, boolean sendDelete, int userId) { EventLog.writeEvent(EventLogTags.NOTIFICATION_CANCEL, pkg, id, tag, mustHaveFlags, mustNotHaveFlags); synchronized (mNotificationList) { - int index = indexOfNotificationLocked(pkg, tag, id); + int index = indexOfNotificationLocked(pkg, tag, id, userId); if (index >= 0) { NotificationRecord r = mNotificationList.get(index); @@ -1202,7 +1222,7 @@ public class NotificationManagerService extends INotificationManager.Stub * {@code mustHaveFlags}. */ boolean cancelAllNotificationsInt(String pkg, int mustHaveFlags, - int mustNotHaveFlags, boolean doit) { + int mustNotHaveFlags, boolean doit, int userId) { EventLog.writeEvent(EventLogTags.NOTIFICATION_CANCEL_ALL, pkg, mustHaveFlags, mustNotHaveFlags); @@ -1211,6 +1231,9 @@ public class NotificationManagerService extends INotificationManager.Stub boolean canceledSomething = false; for (int i = N-1; i >= 0; --i) { NotificationRecord r = mNotificationList.get(i); + if (userId != UserHandle.USER_ALL && r.userId != userId) { + continue; + } if ((r.notification.flags & mustHaveFlags) != mustHaveFlags) { continue; } @@ -1234,30 +1257,30 @@ public class NotificationManagerService extends INotificationManager.Stub } } - @Deprecated - public void cancelNotification(String pkg, int id) { - cancelNotificationWithTag(pkg, null /* tag */, id); - } - - public void cancelNotificationWithTag(String pkg, String tag, int id) { + public void cancelNotificationWithTag(String pkg, String tag, int id, int userId) { checkCallerIsSystemOrSameApp(pkg); + userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), + Binder.getCallingUid(), userId, false, true, "cancelNotificationWithTag", pkg); // Don't allow client applications to cancel foreground service notis. cancelNotification(pkg, tag, id, 0, Binder.getCallingUid() == Process.SYSTEM_UID - ? 0 : Notification.FLAG_FOREGROUND_SERVICE, false); + ? 0 : Notification.FLAG_FOREGROUND_SERVICE, false, userId); } - public void cancelAllNotifications(String pkg) { + public void cancelAllNotifications(String pkg, int userId) { checkCallerIsSystemOrSameApp(pkg); + userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), + Binder.getCallingUid(), userId, true, true, "cancelAllNotifications", pkg); + // Calling from user space, don't allow the canceling of actively // running foreground services. - cancelAllNotificationsInt(pkg, 0, Notification.FLAG_FOREGROUND_SERVICE, true); + cancelAllNotificationsInt(pkg, 0, Notification.FLAG_FOREGROUND_SERVICE, true, userId); } void checkCallerIsSystem() { int uid = Binder.getCallingUid(); - if (uid == Process.SYSTEM_UID || uid == 0) { + if (UserHandle.getAppId(uid) == Process.SYSTEM_UID || uid == 0) { return; } throw new SecurityException("Disallowed call for uid " + uid); @@ -1265,27 +1288,31 @@ public class NotificationManagerService extends INotificationManager.Stub void checkCallerIsSystemOrSameApp(String pkg) { int uid = Binder.getCallingUid(); - if (uid == Process.SYSTEM_UID || uid == 0) { + if (UserHandle.getAppId(uid) == Process.SYSTEM_UID || uid == 0) { return; } try { - ApplicationInfo ai = mContext.getPackageManager().getApplicationInfo( - pkg, 0); - if (!UserId.isSameApp(ai.uid, uid)) { + ApplicationInfo ai = AppGlobals.getPackageManager().getApplicationInfo( + pkg, 0, UserHandle.getCallingUserId()); + if (!UserHandle.isSameApp(ai.uid, uid)) { throw new SecurityException("Calling uid " + uid + " gave package" + pkg + " which is owned by uid " + ai.uid); } - } catch (PackageManager.NameNotFoundException e) { - throw new SecurityException("Unknown package " + pkg); + } catch (RemoteException re) { + throw new SecurityException("Unknown package " + pkg + "\n" + re); } } - void cancelAll() { + void cancelAll(int userId) { synchronized (mNotificationList) { final int N = mNotificationList.size(); for (int i=N-1; i>=0; i--) { NotificationRecord r = mNotificationList.get(i); + if (r.userId != userId) { + continue; + } + if ((r.notification.flags & (Notification.FLAG_ONGOING_EVENT | Notification.FLAG_NO_CLEAR)) == 0) { mNotificationList.remove(i); @@ -1330,12 +1357,15 @@ public class NotificationManagerService extends INotificationManager.Stub } // lock on mNotificationList - private int indexOfNotificationLocked(String pkg, String tag, int id) + private int indexOfNotificationLocked(String pkg, String tag, int id, int userId) { ArrayList<NotificationRecord> list = mNotificationList; final int len = list.size(); for (int i=0; i<len; i++) { NotificationRecord r = list.get(i); + if (r.userId != userId || r.id != id) { + continue; + } if (tag == null) { if (r.tag != null) { continue; @@ -1345,7 +1375,7 @@ public class NotificationManagerService extends INotificationManager.Stub continue; } } - if (r.id == id && r.pkg.equals(pkg)) { + if (r.pkg.equals(pkg)) { return i; } } |
